Commit 09db29fb authored by Timothy M. Shead's avatar Timothy M. Shead

ENH: Refactor test framework into separate event source, player, and dispatcher objects

parent 1dfcea59
......@@ -19,16 +19,16 @@ QT4_WRAP_CPP(MOC_BUILT_SOURCES
pqBasicWidgetEventTranslator.h
pqComboBoxEventTranslator.h
pqDoubleSpinBoxEventTranslator.h
pqEventObserverStdout.h
pqEventObserverXML.h
pqEventDispatcher.h
pqEventPlayer.h
pqEventPlayerXML.h
pqEventTranslator.h
pqLineEditEventTranslator.h
pqMenuEventTranslator.h
pqRecordEventsDialog.h
pqSpinBoxEventTranslator.h
pqStdoutEventObserver.h
pqWidgetEventTranslator.h
pqXMLEventObserver.h
)
SET_DIRECTORY_PROPERTIES(PROPERTIES INCLUDE_DIRECTORIES "${include_dirs_tmp}")
......@@ -65,16 +65,13 @@ ADD_LIBRARY(QtTesting
pqComboBoxEventTranslator.h
pqDoubleSpinBoxEventTranslator.cxx
pqDoubleSpinBoxEventTranslator.h
pqEventObserverStdout.cxx
pqEventObserverStdout.h
pqEventObserverXML.cxx
pqEventObserverXML.h
pqEventDispatcher.cxx
pqEventDispatcher.h
pqEventPlayer.cxx
pqEventPlayer.h
pqEventPlayerXML.cxx
pqEventPlayerXML.h
pqEventTranslator.cxx
pqEventTranslator.h
pqEventSource.h
pqLineEditEventTranslator.cxx
pqLineEditEventTranslator.h
pqMenuEventTranslator.cxx
......@@ -85,8 +82,14 @@ ADD_LIBRARY(QtTesting
pqRecordEventsDialog.h
pqSpinBoxEventTranslator.cxx
pqSpinBoxEventTranslator.h
pqStdoutEventObserver.cxx
pqStdoutEventObserver.h
pqWidgetEventPlayer.h
pqWidgetEventTranslator.h
pqXMLEventObserver.cxx
pqXMLEventObserver.h
pqXMLEventSource.cxx
pqXMLEventSource.h
${MOC_BUILT_SOURCES}
${UI_BUILT_SOURCES}
)
......
/*=========================================================================
Program: ParaView
Module: pqEventDispatcher.cxx
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
ParaView is a free software; you can redistribute it and/or modify it
under the terms of the ParaView license version 1.1.
See License_v1.1.txt for the full ParaView license.
A copy of this license can be obtained by contacting
Kitware Inc.
28 Corporate Drive
Clifton Park, NY 12065
USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "pqEventPlayer.h"
#include "pqEventSource.h"
#include "pqEventDispatcher.h"
#include <QAbstractEventDispatcher>
#include <QtDebug>
#include <QtTest>
////////////////////////////////////////////////////////////////////////////
// pqEventDispatcher::pqImplementation
class pqEventDispatcher::pqImplementation
{
public:
pqImplementation() :
Source(0),
Player(0)
{
}
pqEventSource* Source;
pqEventPlayer* Player;
};
////////////////////////////////////////////////////////////////////////////
// pqEventDispatcher
pqEventDispatcher::pqEventDispatcher() :
Implementation(new pqImplementation())
{
}
pqEventDispatcher::~pqEventDispatcher()
{
delete this->Implementation;
}
void pqEventDispatcher::playEvents(pqEventSource& source, pqEventPlayer& player)
{
if(this->Implementation->Source)
{
qCritical() << "Event dispatcher is already playing";
return;
}
this->Implementation->Source = &source;
this->Implementation->Player = &player;
QApplication::setEffectEnabled(Qt::UI_General, false);
QObject::connect(
QAbstractEventDispatcher::instance(),
SIGNAL(aboutToBlock()),
this,
SLOT(playNextEvent()));
}
void pqEventDispatcher::playNextEvent()
{
QString object;
QString command;
QString arguments;
if(!this->Implementation->Source->getNextEvent(object, command, arguments))
{
this->stopPlayback();
emit this->succeeded();
return;
}
bool error = false;
this->Implementation->Player->playEvent(object, command, arguments, error);
if(error)
{
this->stopPlayback();
emit this->failed();
return;
}
QTest::qWait(100);
}
void pqEventDispatcher::stopPlayback()
{
QObject::disconnect(
QAbstractEventDispatcher::instance(),
SIGNAL(aboutToBlock()),
this,
SLOT(playNextEvent()));
this->Implementation->Source = 0;
this->Implementation->Player = 0;
}
/*=========================================================================
Program: ParaView
Module: pqEventDispatcher.h
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
ParaView is a free software; you can redistribute it and/or modify it
under the terms of the ParaView license version 1.1.
See License_v1.1.txt for the full ParaView license.
A copy of this license can be obtained by contacting
Kitware Inc.
28 Corporate Drive
Clifton Park, NY 12065
USA
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#ifndef _pqEventDispatcher_h
#define _pqEventDispatcher_h
#include "QtTestingExport.h"
#include <QObject>
class pqEventPlayer;
class pqEventSource;
class QTTESTING_EXPORT pqEventDispatcher :
public QObject
{
Q_OBJECT
public:
pqEventDispatcher();
~pqEventDispatcher();
/** Retrieves events from the given event source, dispatching them to
the given event player for test case playback. Note that playback is
asynchronous - the call to playEvents() returns immediately. Callers
must ensure that the source, dispatcher, and player objects remain
in-scope until either the succeeded() or failed() signal is emitted
to indicate that playback has finished. */
void playEvents(pqEventSource& source, pqEventPlayer& player);
signals:
void succeeded();
void failed();
private slots:
void playNextEvent();
private:
void stopPlayback();
class pqImplementation;
pqImplementation* const Implementation;
};
#endif // !_pqEventDispatcher_h
......@@ -41,23 +41,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "pqObjectNaming.h"
#include <QApplication>
#include <QObject>
#include <QWidget>
#include <QtDebug>
#include <QAbstractEventDispatcher>
pqEventPlayer::pqEventPlayer()
{
// connect our play event queue
QObject::connect(this,
SIGNAL(signalPlayEvent(const QString&,
const QString&,
const QString&)),
this,
SLOT(internalPlayEvent(const QString&,
const QString&,
const QString&)),
Qt::QueuedConnection);
}
pqEventPlayer::~pqEventPlayer()
......@@ -85,92 +74,48 @@ void pqEventPlayer::addWidgetEventPlayer(pqWidgetEventPlayer* Player)
}
}
void pqEventPlayer::playEvent(const QString& Object,
const QString& Command, const QString& Arguments)
void pqEventPlayer::playEvent(
const QString& Object,
const QString& Command,
const QString& Arguments,
bool& Error)
{
// queue this on the event loop
// so internalPlayEvent will actually do it
// queuing it prevents callers from being blocked
emit this->signalPlayEvent(Object, Command, Arguments);
}
void pqEventPlayer::internalPlayEvent(const QString& Object,
const QString& Command, const QString& Arguments)
{
// if naming doesn't work out, let quit
// If we can't find an object with the right name, we're done ...
QObject* const object = pqObjectNaming::GetObject(Object);
if(!object)
{
this->exit(false);
Error = true;
return;
}
// loop through players and have one of them handle our event
// Loop through players until the event gets handled ...
bool accepted = false;
bool error = false;
for(int i = 0; i != this->Players.size(); ++i)
{
bool error = false;
if(this->Players[i]->playEvent(object, Command, Arguments, error))
accepted = this->Players[i]->playEvent(object, Command, Arguments, error);
if(accepted)
{
if(error)
{
qCritical() << "Error playing command " << Command << " object " << object;
this->exit(false);
return;
}
return;
break;
}
}
qCritical() << "No player for command " << Command << " object " << object;
this->exit(false);
return;
}
bool pqEventPlayer::exec()
{
// aboutToBlock() from QAbstractEventDispatcher
// is an indication that *absolutely* every Qt event
// has been processed, that's the time when we can say
// "let's play the next test event"
QObject::connect(QAbstractEventDispatcher::instance(),
SIGNAL(aboutToBlock()),
this, SIGNAL(readyPlayEvent()));
this->TopLevelWidgets.clear();
QWidgetList widgets = QApplication::topLevelWidgets();
foreach(QWidget* w, widgets)
// The event wasn't handled at all ...
if(!accepted)
{
this->TopLevelWidgets.append(w);
qCritical() << "Unhandled event " << Command << " object " << object;
Error = true;
return;
}
// start the loop
int ret = EventLoop.exec();
QObject::disconnect(QAbstractEventDispatcher::instance(),
SIGNAL(aboutToBlock()),
this, SIGNAL(readyPlayEvent()));
return ret == 0 ? true : false;
}
void pqEventPlayer::exit(bool ret)
{
// any visible top level widgets made while playing tests
// will be closed
// some/all may be modal, and to exit properly, we have
// to get rid of the modal ones
foreach(QWidget* w, QApplication::topLevelWidgets())
// The event was handled, but there was a problem ...
if(accepted && error)
{
if(!this->TopLevelWidgets.contains(w) && w->isVisible())
{
w->hide();
w->close();
}
qCritical() << "Event error " << Command << " object " << object;
Error = true;
return;
}
// exit our event loop
this->EventLoop.exit(ret ? 0 : 1);
// The event was handled successfully ...
Error = false;
}
......@@ -36,12 +36,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "QtTestingExport.h"
#include <QObject>
#include <QEventLoop>
#include <QString>
#include <QList>
#include <QPointer>
class QObject;
class pqWidgetEventPlayer;
/**
......@@ -68,9 +65,11 @@ event playback, so you can also use this mechanism to
\sa pqWidgetEventPlayer, pqEventTranslator, pqEventPlayerXML
*/
class QTTESTING_EXPORT pqEventPlayer : public QObject
class QTTESTING_EXPORT pqEventPlayer :
public QObject
{
Q_OBJECT
public:
pqEventPlayer();
~pqEventPlayer();
......@@ -82,43 +81,10 @@ public:
/// Adds a new player to the current working set of widget players.
/// pqEventPlayer assumes control of the lifetime of the supplied object.
void addWidgetEventPlayer(pqWidgetEventPlayer*);
/// This method is called with each high-level ParaView event, which
/// will invoke the corresponding low-level Qt functionality in-turn.
/// If there was an error playing the event, the error() signal is emitted
void playEvent(const QString& Object, const QString& Command,
const QString& Arguments = QString());
/// Starts the execution of playing tests
/// The readyPlayEvent() signal will be emitted when
/// things are ready for playEvent() to be called.
/// This is used to simulate a running application
/// while playing back events.
bool exec();
/// notifies the player that we want to quit playing
/// back test events. retVal is the return value from
/// exec()
/// exit(false) is automatically called when there is
/// an error playing an event
void exit(bool retVal);
signals:
/// readyPlayEvent emitted when playEvent is ready
/// for the next playback event
void readyPlayEvent();
// Internals
signals:
void signalPlayEvent(const QString& Object, const QString& Command,
const QString& Arguments = QString());
private slots:
void internalPlayEvent(const QString& Object, const QString& Command,
const QString& Arguments = QString());
void playEvent(const QString& Object, const QString& Command, const QString& Arguments, bool& Error);
private:
pqEventPlayer(const pqEventPlayer&);
......@@ -127,8 +93,6 @@ private:
/// Stores the working set of widget players
QList<pqWidgetEventPlayer*> Players;
QEventLoop EventLoop;
QList<QPointer<QWidget> > TopLevelWidgets;
};
#endif // !_pqEventPlayer_h
......
/*=========================================================================
Program: ParaView
Module: pqEventPlayerXML.h
Module: pqEventSource.h
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
......@@ -30,31 +30,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#ifndef _pqEventPlayerXML_h
#define _pqEventPlayerXML_h
#ifndef _pqEventSource_h
#define _pqEventSource_h
#include "QtTestingExport.h"
#include <QObject>
#include <QString>
#include <QDomNode>
class pqEventPlayer;
class QString;
class QTTESTING_EXPORT pqEventPlayerXML : public QObject
/// Abstract interface for objects that can supply high-level testing events
class QTTESTING_EXPORT pqEventSource
{
Q_OBJECT
public:
/// Loads an XML test case from a file, and plays it with the given player,
/// returning true iff every command was successfully executed
bool playXML(pqEventPlayer& Player, const QString& Path);
virtual ~pqEventSource() {}
protected slots:
void playNextEvent();
/// Retrieves the next available event. Returns true if an event was returned, false if there are no more events
virtual bool getNextEvent(
QString& object,
QString& command,
QString& arguments) = 0;
protected:
QDomNode mDomNode;
pqEventPlayer* Player;
pqEventSource() {}
pqEventSource(const pqEventSource&) {}
pqEventSource& operator=(const pqEventSource&) { return *this; }
};
#endif // !_pqEventPlayerXML_h
#endif // !_pqEventSource_h
......@@ -30,9 +30,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "pqEventObserverXML.h"
#include "pqEventTranslator.h"
#include "pqRecordEventsDialog.h"
#include "pqXMLEventObserver.h"
#include "ui_pqRecordEventsDialog.h"
#include <QPushButton>
......@@ -62,7 +63,7 @@ public:
pqEventTranslator* const Translator;
ofstream File;
pqEventObserverXML Observer;
pqXMLEventObserver Observer;
};
///////////////////////////////////////////////////////////////////////////////////
......
/*=========================================================================
Program: ParaView
Module: pqEventObserverStdout.cxx
Module: pqStdoutEventObserver.cxx
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
......@@ -30,12 +30,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "pqEventObserverStdout.h"
#include "pqStdoutEventObserver.h"
#include <stdio.h>
void pqEventObserverStdout::onRecordEvent(const QString& Widget, const QString& Command, const QString& Arguments)
void pqStdoutEventObserver::onRecordEvent(
const QString& Widget,
const QString& Command,
const QString& Arguments)
{
printf("event: %s %s %s\n", Widget.toAscii().data(), Command.toAscii().data(),
Arguments.toAscii().data());
printf("event: %s %s %s\n",
Widget.toAscii().data(),
Command.toAscii().data(),
Arguments.toAscii().data());
}
/*=========================================================================
Program: ParaView
Module: pqEventObserverStdout.h
Module: pqStdoutEventObserver.h
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
......@@ -30,26 +30,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#ifndef _pqEventObserverStdout_h
#define _pqEventObserverStdout_h
#ifndef _pqStdoutEventObserver_h
#define _pqStdoutEventObserver_h
#include <QObject>
/**
Observes high-level ParaView "events" and writes them to stdout, mainly for debugging purposes.
To use, connect the onRecordEvent() slot to the pqEventTranslator::recordEvent() signal.
Observes high-level ParaView "events" and writes them to stdout,
mainly for debugging purposes. To use, connect the onRecordEvent()
slot to the pqEventTranslator::recordEvent() signal.
\sa pqEventTranslator, pqEventObserverXML
*/
class pqEventObserverStdout :
class pqStdoutEventObserver :
public QObject
{
Q_OBJECT
public slots:
void onRecordEvent(const QString& Widget, const QString& Command, const QString& Arguments);
void onRecordEvent(
const QString& Widget,
const QString& Command,
const QString& Arguments);
};
#endif // !_pqEventObserverStdout_h
#endif // !_pqStdoutEventObserver_h
......@@ -39,7 +39,9 @@ class QObject;
class QString;
/**
Abstract interface for an object that can playback high-level ParaView events by translating them into low-level Qt events, for test-cases, demos, tutorials, etc.
Abstract interface for an object that can playback high-level
ParaView events by translating them into low-level Qt events,
for test-cases, demos, tutorials, etc.
\sa pqEventPlayer
*/
......@@ -49,8 +51,14 @@ class QTTESTING_EXPORT pqWidgetEventPlayer
public:
virtual ~pqWidgetEventPlayer() {}
/// Derivatives should implement this and play-back the given command, returning "true" if they handled the command, and setting Error to "true" if there were any problems.
virtual bool playEvent(QObject* Object, const QString& Command, const QString& Arguments, bool& Error) = 0;
/** Derivatives should implement this and play-back the given command,
returning "true" if they handled the command, and setting Error
to "true" if there were any problems. */
virtual bool playEvent(
QObject* Object,
const QString& Command,
const QString& Arguments,
bool& Error) = 0;
protected:
pqWidgetEventPlayer() {}
......
......@@ -37,7 +37,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <QObject>
/**
Abstract interface for an object that can translate low-level Qt events into high-level, serializable ParaView events, for test-cases, demos, tutorials, etc.
Abstract interface for an object that can translate
low-level Qt events into high-level, serializable ParaView
events, for test-cases, demos, tutorials, etc.
\sa pqEventTranslator
*/
......@@ -49,7 +51,9 @@ class QTTESTING_EXPORT pqWidgetEventTranslator :
public:
virtual ~pqWidgetEventTranslator() {}
/// Derivatives should implement this and translate events into commands, returning "true" if they handled the event, and setting Error to "true" if there were any problems
/** Derivatives should implement this and translate events into commands,
returning "true" if they handled the event, and setting Error
to "true" if there were any problems. */
virtual bool translateEvent(QObject* Object, QEvent* Event, bool& Error) = 0;
signals:
......@@ -58,8 +62,6 @@ signals:
protected:
pqWidgetEventTranslator() {}
private:
pqWidgetEventTranslator(const pqWidgetEventTranslator&);
pqWidgetEventTranslator& operator=(const pqWidgetEventTranslator&);
};
......
/*=========================================================================
Program: ParaView
Module: pqEventObserverXML.cxx
Module: pqXMLEventObserver.cxx
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
......@@ -30,7 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#include "pqEventObserverXML.h"
#include "pqXMLEventObserver.h"
/// Escapes strings so they can be embedded in an XML document
static const QString textToXML(const QString& string)
......@@ -46,21 +46,24 @@ static const QString textToXML(const QString& string)
}
////////////////////////////////////////////////////////////////////////////////////
// pqEventObserverXML
// pqXMLEventObserver
pqEventObserverXML::pqEventObserverXML(ostream& stream) :
pqXMLEventObserver::pqXMLEventObserver(ostream& stream) :
Stream(stream)
{
this->Stream << "<?xml version=\"1.0\" ?>\n";
this->Stream << "<pqevents>\n";
}
pqEventObserverXML::~pqEventObserverXML()
pqXMLEventObserver::~pqXMLEventObserver()
{
this->Stream << "</pqevents>\n";
}
void pqEventObserverXML::onRecordEvent(const QString& Widget, const QString& Command, const QString& Arguments)
void pqXMLEventObserver::onRecordEvent(
const QString& Widget,
const QString& Command,
const QString& Arguments)
{
this->Stream
<< " <pqevent "
......
/*=========================================================================
Program: ParaView
Module: pqEventObserverXML.h
Module: pqXMLEventObserver.h
Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
All rights reserved.
......@@ -30,38 +30,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=========================================================================*/
#ifndef _pqEventObserverXML_h
#define _pqEventObserverXML_h
#ifndef _pqXMLEventObserver_h
#define _pqXMLEventObserver_h
#include <QObject>
#include <vtkIOStream.h>
/**
Observes high-level ParaView events, and serializes them to a stream as XML for possible playback (as a test-case, demo, tutorial, etc).
To use, connect the onRecordEvent() slot to the pqEventTranslator::recordEvent() signal.
Observes high-level ParaView events, and serializes them to a stream as XML
for possible playback (as a test-case, demo, tutorial, etc). To use,
connect the onRecordEvent() slot to the pqEventTranslator::recordEvent()
signal.
\note Output is sent to the stream when this object is initialized, and when it is destroyed, so you must ensure that this object
goes out of scope before trying to playback the stream.