diff --git a/.travis.yml b/.travis.yml index 32c366ed..b2231f39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ matrix: - os: osx env: GMOCK_PATH=/usr/src/gmock - os: osx - compiler: gcc #does anyone on osx use it? + compiler: gcc addons: apt: @@ -30,6 +30,7 @@ addons: - libboost-test-dev - google-mock - ninja-build + - qtbase5-dev before_install: - if [[ "${TRAVIS_OS_NAME}" = "osx" ]]; then brew update && brew install ninja; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index ce78146c..e9c5f057 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,25 @@ elseif(MSVC) #set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /analyze") endif() +# +# Qt +# + +find_package(Qt5Core QUIET) +find_package(Qt5Widgets QUIET) +find_package(Qt5Test QUIET) +find_package(Qt5Concurrent QUIET) + +if(${Qt5Core_FOUND} AND ${Qt5Test_FOUND}) + message(STATUS "Using Qt version: ${Qt5Core_VERSION_STRING}") + set(CMAKE_INCLUDE_CURRENT_DIR ON) + set(CMAKE_AUTOMOC ON) + if (Qt5_POSITION_INDEPENDENT_CODE) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + endif() + set(QT_LIBRARIES Qt5::Core Qt5::Widgets Qt5::Test) +endif() + # # Boost # @@ -107,11 +126,8 @@ endif() # set(CUKE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) - include_directories(${CUKE_INCLUDE_DIR}) - set(CUKE_LIBRARIES cucumber-cpp ${CUKE_EXTRA_LIBRARIES}) - add_subdirectory(src) # @@ -176,3 +192,23 @@ endif() if(CUKE_ENABLE_EXAMPLES) add_subdirectory(examples) endif() + +#check if c++11 is nedded +if(${Qt5Core_FOUND} AND ${Qt5Test_FOUND}) + find_program(QMAKE_EXECUTABLE NAMES qmake HINTS ${QTDIR} ENV QTDIR PATH_SUFFIXES bin) + execute_process(COMMAND ${QMAKE_EXECUTABLE} -query QT_VERSION OUTPUT_VARIABLE QT_VERSION) + if(QT_VERSION GREATER 5.6.99) + message(STATUS "C++11 is needed from Qt version 5.7.0, building with c++11 enabled") + set_property(TARGET cucumber-cpp PROPERTY CXX_STANDARD 11) + set_property(TARGET cucumber-cpp-nomain PROPERTY CXX_STANDARD 11) + if(NOT CUKE_DISABLE_UNIT_TESTS) + set_property(TARGET QtTestDriverTest PROPERTY CXX_STANDARD 11) + endif() + if(CUKE_ENABLE_EXAMPLES) + set_property(TARGET libcalcqt PROPERTY CXX_STANDARD 11) + set_property(TARGET calcqt PROPERTY CXX_STANDARD 11) + set_property(TARGET QtTestCalculatorQtSteps PROPERTY CXX_STANDARD 11) + endif() + endif() +endif() + diff --git a/README.md b/README.md index d92cedc8..6382c6ab 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,9 @@ It relies on a few libraries: Optional for the GTest driver. By default downloaded and built by CMake. * [GMock](http://code.google.com/p/googlemock/) 1.6 or later. Optional for the internal test suite. By default downloaded and built by CMake. -* [Qt 4 or 5](http://qt-project.org/). Optional for the CalcQt example. +* [Qt](http://www.qt.io/) + Optional for the CalcQt example: version 4.x or 5.x, modules: *core*, *widgets* and *test*. + Optional for QtTest driver: version 5.x, modules: *core* and *test*. This header-only library is included in the source code: diff --git a/appveyor.bat b/appveyor.bat new file mode 100644 index 00000000..81c919c1 --- /dev/null +++ b/appveyor.bat @@ -0,0 +1,13 @@ +git submodule init +git submodule update +call gem install bundle +call bundle install +REM bundle env +if "%build%"=="mingw" bash -lc "pacman --needed --noconfirm -S mingw-w64-%MINGW_ARCH%-boost +if "%build%"=="msvc" call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %PLATFORM% + +cmake -E make_directory build +cmake -E chdir build cmake -G "%CMAKE_GENERATOR%" -DCUKE_ENABLE_EXAMPLES=on -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_INCLUDEDIR="%BOOST_INCLUDEDIR%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" -DQT_QMAKE_EXECUTABLE="%QT_DIR%/bin/qmake.exe" .. +cmake --build build +cmake --build build --target test +cmake --build build --target features diff --git a/appveyor.yml b/appveyor.yml index d9ed4f28..36440221 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,28 +28,22 @@ environment: BOOST_LIBRARYDIR: C:\Libraries\boost_1_59_0\lib32-msvc-14.0 BOOST_INCLUDEDIR: C:\Libraries\boost_1_59_0\boost CMAKE_GENERATOR: 'NMake Makefiles' + QT_DIR: C:\Qt\5.7\msvc2015 - build: msvc platform: x64 BOOST_ROOT: C:\Libraries\boost_1_59_0 BOOST_INCLUDEDIR: C:\Libraries\boost_1_59_0\boost BOOST_LIBRARYDIR: C:\Libraries\boost_1_59_0\lib64-msvc-14.0 CMAKE_GENERATOR: 'NMake Makefiles' + QT_DIR: C:\Qt\5.7\msvc2015_64 install: -- git submodule init -- git submodule update - set PATH=C:\Ruby%RUBY_VERSION%\bin;%BOOST_LIBRARYDIR%;%PATH% -- gem install bundle -- bundle install -- bundle env - if "%build%"=="mingw" set PATH=%MINGW_ROOT%\bin;C:\msys64\usr\bin\;%PATH% -- if "%build%"=="mingw" bash -lc "pacman --needed --noconfirm -S mingw-w64-%MINGW_ARCH%-boost +- if "%build%"=="msvc" set PATH=%QT_DIR%\bin;%PATH% build_script: -- cmd: if "%build%"=="msvc" call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %PLATFORM% -- cmd: cmake -E make_directory build -- cmd: cmake -E chdir build cmake -G "%CMAKE_GENERATOR%" -DCUKE_ENABLE_EXAMPLES=ON -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_INCLUDEDIR="%BOOST_INCLUDEDIR%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" .. -- cmd: cmake --build build +- cmd: call appveyor.bat test_script: - cmd: set CTEST_OUTPUT_ON_FAILURE=ON diff --git a/examples/Calc/CMakeLists.txt b/examples/Calc/CMakeLists.txt index 7157f3ec..7ba2257b 100644 --- a/examples/Calc/CMakeLists.txt +++ b/examples/Calc/CMakeLists.txt @@ -14,3 +14,9 @@ if(Boost_UNIT_TEST_FRAMEWORK_FOUND) add_executable(BoostCalculatorSteps features/step_definitions/BoostCalculatorSteps) target_link_libraries(BoostCalculatorSteps Calc ${CUKE_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) endif() + +if(${Qt5Core_FOUND} AND ${Qt5Test_FOUND}) + include_directories(${Qt5Core_INCLUDE_DIRS}) + add_executable(QtTestCalculatorSteps features/step_definitions/QtTestCalculatorSteps) + target_link_libraries(QtTestCalculatorSteps Calc Qt5::Core Qt5::Test ${CUKE_LIBRARIES}) +endif() diff --git a/examples/Calc/features/step_definitions/QtTestCalculatorSteps.cpp b/examples/Calc/features/step_definitions/QtTestCalculatorSteps.cpp new file mode 100644 index 00000000..73de0f8b --- /dev/null +++ b/examples/Calc/features/step_definitions/QtTestCalculatorSteps.cpp @@ -0,0 +1,38 @@ +#include +#include + +#include "Calculator.h" + +using cucumber::ScenarioScope; + +struct CalcCtx { + Calculator calc; + double result; +}; + +GIVEN("^I have entered (\\d+) into the calculator$") { + REGEX_PARAM(double, n); + ScenarioScope context; + + context->calc.push(n); +} + +WHEN("^I press add") { + ScenarioScope context; + + context->result = context->calc.add(); +} + +WHEN("^I press divide") { + ScenarioScope context; + + context->result = context->calc.divide(); +} + +THEN("^the result should be (.*) on the screen$") { + REGEX_PARAM(double, expected); + ScenarioScope context; + + QCOMPARE(expected, context->result); +} + diff --git a/examples/CalcQt/CMakeLists.txt b/examples/CalcQt/CMakeLists.txt index 998f16bc..69e91417 100644 --- a/examples/CalcQt/CMakeLists.txt +++ b/examples/CalcQt/CMakeLists.txt @@ -18,6 +18,9 @@ if(${Qt5Core_FOUND} AND ${Qt5Widgets_FOUND} AND ${Qt5Test_FOUND}) add_executable(calcqt ${CALCQT_SOURCES}) target_link_libraries(calcqt libcalcqt ${QT_LIBRARIES}) + + add_executable(QtTestCalculatorQtSteps features/step_definitions/QtTestCalculatorQtSteps) + target_link_libraries(QtTestCalculatorQtSteps libcalcqt ${QT_LIBRARIES} ${CUKE_LIBRARIES}) else() find_package(Qt4 COMPONENTS QtCore QtGui QtTest) if(QT4_FOUND) diff --git a/examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp b/examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp new file mode 100644 index 00000000..008c0932 --- /dev/null +++ b/examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include "CalculatorWidget.h" + +static int argc = 0; +static QApplication app(argc, 0); +static int milliseconds = -1; + +int millisecondsToWait() { + if (milliseconds < 0) + { + char* envVariable = getenv("CALCQT_STEP_DELAY"); + milliseconds = (0 != envVariable) ? atoi(envVariable) : 0; + } + return milliseconds; +} + +std::istream& operator>> (std::istream& in, QString& val) { std::string s; in >> s; val = s.c_str(); return in; } +std::ostream& operator<< (std::ostream& out, const QString& val) { out << val.toLatin1().data(); return out; } + +GIVEN("^I just turned on the calculator$") { + cucumber::ScenarioScope calculator; + calculator->move(0, 0); + calculator->show(); +#if QT_VERSION >= 0x050000 + QTest::qWaitForWindowExposed(calculator.get()); +#else + QTest::qWaitForWindowShown(calculator.get()); +#endif + QTest::qWait(millisecondsToWait()); +} + +WHEN("^I press (\\d+)$") { + REGEX_PARAM(unsigned int, n); + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_0 + n, Qt::NoModifier, millisecondsToWait()); +} + +WHEN("^I press add") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Plus, Qt::NoModifier, millisecondsToWait()); +} + +WHEN("^I press calculate") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Return, Qt::NoModifier, millisecondsToWait()); +} + +WHEN("^I press clear") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Escape, Qt::NoModifier, millisecondsToWait()); +} + +WHEN("^I press subtract") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Minus, Qt::NoModifier, millisecondsToWait()); +} + +THEN("^the display should be empty$") { + cucumber::ScenarioScope calculator; + QCOMPARE(0, calculator->display().size()); + QTest::qWait(millisecondsToWait()); +} + +THEN("^the display should show (.*)$") { + REGEX_PARAM(QString, expected); + cucumber::ScenarioScope calculator; + QCOMPARE(calculator->display(), expected); + QTest::qWait(millisecondsToWait()); +} diff --git a/include/cucumber-cpp/internal/drivers/DriverSelector.hpp b/include/cucumber-cpp/internal/drivers/DriverSelector.hpp index f4ac8567..ad334df2 100644 --- a/include/cucumber-cpp/internal/drivers/DriverSelector.hpp +++ b/include/cucumber-cpp/internal/drivers/DriverSelector.hpp @@ -2,4 +2,7 @@ #include "GTestDriver.hpp" #elif defined(BOOST_TEST_CASE) #include "BoostDriver.hpp" +#elif defined(QTEST_H) + #include "QtTestDriver.hpp" #endif + diff --git a/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp b/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp new file mode 100644 index 00000000..5160ed17 --- /dev/null +++ b/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp @@ -0,0 +1,23 @@ +#ifndef CUKE_QTTESTDRIVER_HPP_ +#define CUKE_QTTESTDRIVER_HPP_ + +#include "../step/StepManager.hpp" + +namespace cucumber { +namespace internal { + +class QtTestStep : public BasicStep{ + friend class QtTestObject; +public: + QtTestStep(): BasicStep() {} + +protected: + const InvokeResult invokeStepBody(); +}; + +#define STEP_INHERITANCE(step_name) ::cucumber::internal::QtTestStep + +} +} + +#endif /* CUKE_QTTESTDRIVER_HPP_ */ diff --git a/include/cucumber-cpp/internal/utils/qtCapture.hpp b/include/cucumber-cpp/internal/utils/qtCapture.hpp new file mode 100644 index 00000000..54c632cf --- /dev/null +++ b/include/cucumber-cpp/internal/utils/qtCapture.hpp @@ -0,0 +1,181 @@ +/* Based on Sir Digby Chicken post from: + * http://stackoverflow.com/questions/5419356/redirect-stdout-stderr-to-a-string + * who granted his work on BSD license + * adjusted for Qt by konserw + */ +#ifdef _MSC_VER +#include +#include +#define popen _popen +#define pclose _pclose +#define stat _stat +#define dup _dup +#define dup2 _dup2 +#define fileno _fileno +#define close _close +#define pipe _pipe +#define read _read +#define eof _eof +#else +#include +#endif + +#include +#include + +#ifndef STD_OUT_FD +#define STD_OUT_FD (fileno(stdout)) +#endif +#ifndef STD_ERR_FD +#define STD_ERR_FD (fileno(stderr)) +#endif + +class qtCapture { +public: + static void Init() { + // make stdout & stderr streams unbuffered + // so that we don't need to flush the streams + // before capture and after capture + // (fflush can cause a deadlock if the stream is currently being + QMutexLocker locker(&m_mutex); + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + } + + static void BeginCapture() { + QMutexLocker locker(&m_mutex); + if (m_capturing) + return; + + secure_pipe(m_pipe); + m_oldStdOut = secure_dup(STD_OUT_FD); + m_oldStdErr = secure_dup(STD_ERR_FD); + secure_dup2(m_pipe[WRITE], STD_OUT_FD); + secure_dup2(m_pipe[WRITE], STD_ERR_FD); + m_capturing = true; +#ifndef _MSC_VER + secure_close(m_pipe[WRITE]); +#endif + } + + static bool IsCapturing() { + QMutexLocker locker(&m_mutex); + return m_capturing; + } + + static void EndCapture() { + QMutexLocker locker(&m_mutex); + if (!m_capturing) + return; + + m_captured.clear(); + secure_dup2(m_oldStdOut, STD_OUT_FD); + secure_dup2(m_oldStdErr, STD_ERR_FD); + + const int bufSize = 1025; + char buf[bufSize]; + int bytesRead = 0; + bool fd_blocked(false); + do { + bytesRead = 0; + fd_blocked = false; +#ifdef _MSC_VER + if (!eof(m_pipe[READ])) + bytesRead = read(m_pipe[READ], buf, bufSize-1); +#else + bytesRead = read(m_pipe[READ], buf, bufSize-1); +#endif + if (bytesRead > 0) { + buf[bytesRead] = 0; + m_captured += buf; + } else if (bytesRead < 0) { + fd_blocked = (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR); + if (fd_blocked) + QThread::msleep(10); + } + } + while(fd_blocked || bytesRead == (bufSize-1)); + + secure_close(m_oldStdOut); + secure_close(m_oldStdErr); + secure_close(m_pipe[READ]); +#ifdef _MSC_VER + secure_close(m_pipe[WRITE]); +#endif + m_capturing = false; + } + + static std::string GetCapture() { + QMutexLocker locker(&m_mutex); + return m_captured; + } + +private: + enum PIPES { READ, WRITE }; + + static int secure_dup(int src) { + int ret = -1; + bool fd_blocked = false; + do { + ret = dup(src); + fd_blocked = (errno == EINTR || errno == EBUSY); + if(fd_blocked) + QThread::msleep(10); + } while (ret < 0); + return ret; + } + + static void secure_pipe(int * pipes) { + int ret = -1; + bool fd_blocked = false; + do { +#ifdef _MSC_VER + ret = pipe(pipes, 65536, O_BINARY); +#else + ret = pipe(pipes) == -1; +#endif + fd_blocked = (errno == EINTR || errno == EBUSY); + if (fd_blocked) + QThread::msleep(10); + } while (ret < 0); + } + + static void secure_dup2(int src, int dest) { + int ret = -1; + bool fd_blocked = false; + do { + ret = dup2(src,dest); + fd_blocked = (errno == EINTR || errno == EBUSY); + if (fd_blocked) + QThread::msleep(10); + } while (ret < 0); + } + + static void secure_close(int & fd) { + int ret = -1; + bool fd_blocked = false; + do { + ret = close(fd); + fd_blocked = (errno == EINTR); + if (fd_blocked) + QThread::msleep(10); + } while (ret < 0); + + fd = -1; + } + + static int m_pipe[2]; + static int m_oldStdOut; + static int m_oldStdErr; + static bool m_capturing; + static QMutex m_mutex; + static std::string m_captured; +}; + +// actually define vars. +int qtCapture::m_pipe[2]; +int qtCapture::m_oldStdOut; +int qtCapture::m_oldStdErr; +bool qtCapture::m_capturing; +QMutex qtCapture::m_mutex; +std::string qtCapture::m_captured; diff --git a/osx-install-qt.sh b/osx-install-qt.sh new file mode 100755 index 00000000..ec27cd1e --- /dev/null +++ b/osx-install-qt.sh @@ -0,0 +1,14 @@ +#qt installation based on https://github.com/benlau/qtci/blob/master/recipes/qt-5.7-osx + +echo Downloading Qt +DOWNLOAD_URL=https://download.qt.io/archive/qt/5.7/5.7.0/qt-opensource-mac-x64-clang-5.7.0.dmg +INSTALLER=`basename $DOWNLOAD_URL` +INSTALLER_NAME=${INSTALLER%.*} +APPFILE=/Volumes/${INSTALLER_NAME}/${INSTALLER_NAME}.app/Contents/MacOS/${INSTALLER_NAME} +wget -c $DOWNLOAD_URL +hdiutil mount ${INSTALLER} +echo Installing Qt +wget -c https://raw.githubusercontent.com/benlau/qtci/master/bin/extract-qt-installer +chmod +x ./extract-qt-installer +./extract-qt-installer $APPFILE $PWD/Qt +export PATH=$PWD/Qt/5.7/clang_64/bin:$PATH diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f54a02b..40992d02 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,6 +15,11 @@ set(CUKE_SOURCES connectors/wire/WireProtocolCommands.cpp ) +if(${Qt5Core_FOUND} AND ${Qt5Test_FOUND}) + include_directories(${Qt5Core_INCLUDE_DIRS}) + list(APPEND CUKE_SOURCES drivers/QtTestDriver.cpp) +endif() + if(GTEST_FOUND) list(APPEND CUKE_DEP_LIBRARIES GTest::GTest) list(APPEND CUKE_SOURCES drivers/GTestDriver.cpp) diff --git a/src/drivers/QtTestDriver.cpp b/src/drivers/QtTestDriver.cpp new file mode 100644 index 00000000..c639b932 --- /dev/null +++ b/src/drivers/QtTestDriver.cpp @@ -0,0 +1,48 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cucumber-cpp/internal/utils/qtCapture.hpp" + +namespace cucumber { +namespace internal { + +class QtTestObject: public QObject { + Q_OBJECT +public: + QtTestObject(QtTestStep* qtTestStep): step(qtTestStep) {} + virtual ~QtTestObject() {} + +protected: + QtTestStep* step; + +private slots: + void test() const { + step->body(); + } +}; + +const InvokeResult QtTestStep::invokeStepBody() { + QtTestObject testObject(this); + + qtCapture::Init(); + qtCapture::BeginCapture(); + int returnValue = QTest::qExec(&testObject, 0, NULL); + qtCapture::EndCapture(); + + if(returnValue == 0) + return InvokeResult::success(); + else + return InvokeResult::failure(qtCapture::GetCapture()); +} + +} +} + +#include "QtTestDriver.moc" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8becb2db..90d44b9f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -36,6 +36,10 @@ if(GMOCK_FOUND) cuke_add_driver_test(integration/drivers/GTestDriverTest ${CUKE_GTEST_LIBRARIES}) endif() +if(${Qt5Core_FOUND} AND ${Qt5Test_FOUND}) + cuke_add_driver_test(integration/drivers/QtTestDriverTest ${QT_LIBRARIES}) +endif() + if(Boost_UNIT_TEST_FRAMEWORK_FOUND) cuke_add_driver_test(integration/drivers/BoostDriverTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) endif() diff --git a/tests/integration/WireProtocolTest.cpp b/tests/integration/WireProtocolTest.cpp index fa12c714..72d59388 100644 --- a/tests/integration/WireProtocolTest.cpp +++ b/tests/integration/WireProtocolTest.cpp @@ -25,9 +25,7 @@ class MockCukeEngine : public CukeEngine { EXPECT_THAT(typeid(classname).name(), StrEq(typeid(expression).name())) #define EXPECT_PTRTYPE(classname, expression) \ - EXPECT_TYPE(classname, *expression) - - + EXPECT_NE(dynamic_cast(expression), (void*)NULL) class WireMessageCodecTest : public Test { public: diff --git a/tests/integration/drivers/QtTestDriverTest.cpp b/tests/integration/drivers/QtTestDriverTest.cpp new file mode 100644 index 00000000..9a07e27e --- /dev/null +++ b/tests/integration/drivers/QtTestDriverTest.cpp @@ -0,0 +1,65 @@ +#include +#include + +#include "../../utils/DriverTestRunner.hpp" + +using namespace cucumber; + +THEN(SUCCEED_MATCHER) { + ScenarioScope ctx; + QVERIFY(true); +} + +THEN(FAIL_MATCHER) { + ScenarioScope ctx; + QVERIFY(false); +} + +THEN(PENDING_MATCHER_1) { + pending(); +} + +THEN(PENDING_MATCHER_2) { + pending(PENDING_DESCRIPTION); +} + +using namespace cucumber::internal; + +class QtTestStepDouble : public QtTestStep { +public: + QtTestStepDouble() : QtTestStep() { + testRun = false; + } + + const InvokeResult invokeStepBody() { + return QtTestStep::invokeStepBody(); + } + + void body() { + testRun = true; + } + + bool testRun; +}; + +class QtTestDriverTest : public DriverTest { +public: + virtual void runAllTests() { + stepInvocationRunsStepBody(); + DriverTest::runAllTests(); + } + +private: + void stepInvocationRunsStepBody() { + QtTestStepDouble framework; + expectFalse("The test body has not been run", framework.testRun); + framework.invokeStepBody(); + expectTrue("The test body has been run", framework.testRun); + } +}; + +int main() { + QtTestDriverTest test; + return test.run(); +} + diff --git a/travis.sh b/travis.sh index afb6d000..dd7e7ddb 100755 --- a/travis.sh +++ b/travis.sh @@ -1,5 +1,8 @@ #!/bin/sh set -e #break script on non-zero exitcode from any command + +if [ "${TRAVIS_OS_NAME}" = "osx" ]; then source osx-install-qt.sh; fi + gem install bundler bundle install @@ -19,6 +22,7 @@ cmake --build build --target features GTEST=build/examples/Calc/GTestCalculatorSteps BOOST=build/examples/Calc/BoostCalculatorSteps +QTTEST=build/examples/Calc/QtTestCalculatorSteps if [ -f $GTEST ]; then $GTEST >/dev/null & cucumber examples/Calc @@ -29,3 +33,8 @@ if [ -f $BOOST ]; then cucumber examples/Calc wait fi +if [ -f $QTTEST ]; then + $QTTEST >/dev/null & + cucumber examples/Calc + wait +fi