diff --git a/.travis.yml b/.travis.yml index 05685dcb..d466ae0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: cpp os: - - osx - linux sudo: required dist: trusty @@ -13,14 +12,19 @@ env: - GMOCK_PATH=/usr/src/gmock #1.6.0 from ubuntu trusty repo matrix: exclude: - - os: osx - env: GMOCK_PATH=/usr/src/gmock - - os: osx - compiler: gcc #does anyone on osx use it? + - os: linux + compiler: gcc + env: GMOCK_VER=1.8.0 include: - os: linux compiler: gcc env: GMOCK_VER=1.8.0 VALGRIND_TESTS=ON + - os: osx + compiler: clang + env: GMOCK_VER=1.8.0 QTDIR=/usr/local/Cellar/qt5/5.8.0_1 + - os: osx + compiler: clang + env: GMOCK_VER=1.7.0 addons: apt: @@ -35,9 +39,10 @@ addons: - google-mock - ninja-build - valgrind + - qtbase5-dev before_install: - - if [[ "${TRAVIS_OS_NAME}" = "osx" ]]; then brew update && brew install ninja; fi + - if [[ "${TRAVIS_OS_NAME}" = "osx" ]]; then brew update && brew install ninja qt5; fi script: ./travis.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 576afe0d..05486c3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,19 +1,20 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.1) project(Cucumber-Cpp) -set(CUKE_USE_STATIC_BOOST ${WIN32} CACHE BOOL "Statically link Boost (except boost::test)") -set(CUKE_USE_STATIC_GTEST ON CACHE BOOL "Statically link Google Test") - -set(CUKE_DISABLE_BOOST_TEST OFF CACHE BOOL "Disable boost:test") -set(CUKE_DISABLE_GTEST OFF CACHE BOOL "Disable Google Test framework") -set(CUKE_DISABLE_UNIT_TESTS OFF CACHE BOOL "Disable unit tests") -set(CUKE_DISABLE_E2E_TESTS OFF CACHE BOOL "Disable end-to-end tests") -set(CUKE_ENABLE_EXAMPLES OFF CACHE BOOL "Enable the examples") +option(CUKE_USE_STATIC_BOOST "Statically link Boost (except boost::test)" ${WIN32}) +option(CUKE_USE_STATIC_GTEST "Statically link Google Test" ON) +option(CUKE_DISABLE_BOOST_TEST "Disable boost:test" OFF) +option(CUKE_DISABLE_GTEST "Disable Google Test framework" OFF) +option(CUKE_DISABLE_UNIT_TESTS "Disable unit tests" OFF) +option(CUKE_DISABLE_E2E_TESTS "Disable end-to-end tests" OFF) +option(CUKE_ENABLE_EXAMPLES "Enable the examples" OFF) +option(VALGRIND_TESTS "Run tests within Valgrind" OFF) +option(CUKE_DISABLE_QT "Disable using Qt framework" OFF) set(GMOCK_SRC_DIR "" CACHE STRING "Google Mock framework sources path (otherwise downloaded)") set(GMOCK_VER "1.7.0" CACHE STRING "Google Mock framework version to be used") -option(VALGRIND_TESTS "Run tests within Valgrind" OFF) +set(ignoreMe "${QT_QMAKE_EXECUTABLE}") #supress warning set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) # @@ -103,6 +104,36 @@ if(NOT CUKE_DISABLE_GTEST) endif() endif() +# +# Qt +# + +if(NOT CUKE_DISABLE_QT) + set(CMAKE_PREFIX_PATH $ENV{QTDIR}) + find_package(Qt5Core) + find_package(Qt5Widgets) + find_package(Qt5Test) + + if(${Qt5Core_FOUND} AND ${Qt5Widgets_FOUND} AND ${Qt5Test_FOUND}) + set(QT5_FOUND true) + message(STATUS "Found Qt version: ${Qt5Core_VERSION_STRING}") + if (Qt5_POSITION_INDEPENDENT_CODE) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + endif() + set(QT_LIBRARIES Qt5::Core Qt5::Widgets Qt5::Test) + if(NOT ${Qt5Core_VERSION_STRING} VERSION_LESS 5.7) + message(STATUS "C++11 is needed from Qt version 5.7.0, building with c++11 enabled") + set(CMAKE_CXX_STANDARD 11) + endif() + else() + find_package(Qt4 COMPONENTS QtCore QtGui QtTest) + if(QT4_FOUND) + set(QT_LIBRARIES Qt4::QtCore Qt4::QtGui Qt4::QtTest) + include(${QT_USE_FILE}) + endif() + endif() +endif() + # # Valgrind # @@ -154,11 +185,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) # @@ -223,3 +251,4 @@ endif() if(CUKE_ENABLE_EXAMPLES) add_subdirectory(examples) endif() + diff --git a/README.md b/README.md index d92cedc8..a548d297 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ with [CPP]. It relies on a few executables: -* [cmake](https://cmake.org/download/) 2.8.12 or later. +* [cmake](https://cmake.org/download/) 3.1 or later. Required to setup environment and build software It relies on a few libraries: diff --git a/appveyor.bat b/appveyor.bat new file mode 100644 index 00000000..1d6a25ce --- /dev/null +++ b/appveyor.bat @@ -0,0 +1,20 @@ +set PATH=C:\Ruby200\bin;%BOOST_LIBRARYDIR%;%PATH% +if defined MINGW_ROOT set PATH=%MINGW_ROOT%\bin;C:\msys64\usr\bin\;%PATH% +if defined QT_DIR set PATH=%QT_DIR%\bin;%PATH% +if "%CMAKE_GENERATOR%"=="NMake Makefiles" call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" %PLATFORM% +echo %PATH% + +git submodule init +git submodule update +call gem install bundle +call bundle install +if defined MINGW_ARCH bash -lc "pacman --needed --noconfirm -S mingw-w64-%MINGW_ARCH%-boost + +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 + +set CTEST_OUTPUT_ON_FAILURE=ON +cmake --build build --target test +cmake --build build --target features + diff --git a/appveyor.yml b/appveyor.yml index d9ed4f28..3f5307d5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,59 +2,35 @@ version: "{branch}-ci-{build}" os: Visual Studio 2015 environment: - RUBY_VERSION: 200 matrix: - - build: mingw - platform: x86 + - CMAKE_GENERATOR: 'MSYS Makefiles' MINGW_ARCH: i686 - MSYSTEM: MINGW32 MINGW_ROOT: C:\msys64\mingw32 BOOST_ROOT: C:\msys64\mingw32 BOOST_LIBRARYDIR: C:\msys64\mingw32\lib BOOST_INCLUDEDIR: C:\msys64\mingw32\include\boost - CMAKE_GENERATOR: 'MSYS Makefiles' - - build: mingw - platform: x64 + QT_DIR: C:\Qt\5.8\mingw53_32 + - CMAKE_GENERATOR: 'MSYS Makefiles' MINGW_ARCH: x86_64 - MSYSTEM: MINGW64 MINGW_ROOT: C:\msys64\mingw64 BOOST_ROOT: C:\msys64\mingw64 BOOST_LIBRARYDIR: C:\msys64\mingw64\lib BOOST_INCLUDEDIR: C:\msys64\mingw64\include\boost - CMAKE_GENERATOR: 'MSYS Makefiles' - - build: msvc + - CMAKE_GENERATOR: 'NMake Makefiles' platform: x86 BOOST_ROOT: C:\Libraries\boost_1_59_0 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' - - build: msvc + QT_DIR: C:\Qt\5.6\msvc2015 + - CMAKE_GENERATOR: 'NMake Makefiles' 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' - -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 + QT_DIR: C:\Qt\5.8\msvc2015_64 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 - -test_script: -- cmd: set CTEST_OUTPUT_ON_FAILURE=ON -- cmd: cmake --build build --target test -- cmd: cmake --build build --target features +- cmd: call appveyor.bat notifications: - provider: Email diff --git a/examples/Calc/CMakeLists.txt b/examples/Calc/CMakeLists.txt index 7157f3ec..c6cda24f 100644 --- a/examples/Calc/CMakeLists.txt +++ b/examples/Calc/CMakeLists.txt @@ -14,3 +14,8 @@ 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(QT5_FOUND) + add_executable(QtTestCalculatorSteps features/step_definitions/QtTestCalculatorSteps) + target_link_libraries(QtTestCalculatorSteps Calc ${QT_LIBRARIES} ${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..3b6c9589 --- /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(context->result, expected); +} + diff --git a/examples/CalcQt/CMakeLists.txt b/examples/CalcQt/CMakeLists.txt index 998f16bc..80a2a3a3 100644 --- a/examples/CalcQt/CMakeLists.txt +++ b/examples/CalcQt/CMakeLists.txt @@ -1,36 +1,22 @@ project(CalcQt) set(CALCQT_HEADERS src/CalculatorWidget.h) -set(CALCQT_SOURCES src/CalcQt.cpp src/CalculatorWidget.cpp) -include_directories(${CUKE_INCLUDE_DIRS} src) +include_directories(src) -find_package(Qt5Core QUIET) -find_package(Qt5Widgets QUIET) -find_package(Qt5Test QUIET) - -if(${Qt5Core_FOUND} AND ${Qt5Widgets_FOUND} AND ${Qt5Test_FOUND}) - set(CMAKE_INCLUDE_CURRENT_DIR ON) - set(CMAKE_AUTOMOC ON) - set(QT_LIBRARIES Qt5::Core Qt5::Widgets Qt5::Test) - - add_library(libcalcqt src/CalculatorWidget.cpp ${CALCQT_HEADERS}) +if(QT_LIBRARIES) + if(QT4_FOUND) + qt4_wrap_cpp(CALCQT_MOC ${CALCQT_HEADERS}) + else() + qt5_wrap_cpp(CALCQT_MOC ${CALCQT_HEADERS}) + add_executable(QtTestCalculatorQtSteps features/step_definitions/QtTestCalculatorQtSteps) + target_link_libraries(QtTestCalculatorQtSteps libcalcqt ${QT_LIBRARIES} ${CUKE_LIBRARIES}) + endif() + add_library(libcalcqt src/CalculatorWidget.cpp ${CALCQT_MOC}) target_link_libraries(libcalcqt ${QT_LIBRARIES}) - add_executable(calcqt ${CALCQT_SOURCES}) + add_executable(calcqt src/CalcQt.cpp) target_link_libraries(calcqt libcalcqt ${QT_LIBRARIES}) -else() - find_package(Qt4 COMPONENTS QtCore QtGui QtTest) - if(QT4_FOUND) - include(${QT_USE_FILE}) - qt4_wrap_cpp(CALCQT_HEADERS_MOC ${CALCQT_HEADERS}) - add_library(libcalcqt src/CalculatorWidget ${CALCQT_HEADERS_MOC}) - - add_executable(calcqt ${CALCQT_SOURCES} ${CALCQT_HEADERS_MOC}) - target_link_libraries(calcqt ${QT_LIBRARIES}) - endif() -endif() -if(QT_LIBRARIES) if(Boost_UNIT_TEST_FRAMEWORK_FOUND) include_directories(${Boost_INCLUDE_DIRS}) add_executable(BoostCalculatorQtSteps features/step_definitions/BoostCalculatorQtSteps) diff --git a/examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp b/examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp new file mode 100644 index 00000000..25e34e50 --- /dev/null +++ b/examples/CalcQt/features/step_definitions/QtTestCalculatorQtSteps.cpp @@ -0,0 +1,73 @@ +#include +#include "cucumber-cpp/autodetect.hpp" +#include +#include +#include "CalculatorWidget.h" + +std::istream& operator>> (std::istream& in, QString& val) { std::string s; in >> s; val = QString::fromLocal8Bit(s.c_str()); return in; } +std::ostream& operator<< (std::ostream& out, const QString& val) { out << val.toLocal8Bit().data(); return out; } + +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 = (envVariable) ? atoi(envVariable) : 0; + } + return milliseconds; +} + +AFTER_STEP(){ + QTest::qWait(millisecondsToWait()); +} + +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 +} + +WHEN("^I press (\\d+)$") { + REGEX_PARAM(unsigned int, n); + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_0 + n, Qt::NoModifier, 0); +} + +WHEN("^I press add") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Plus, Qt::NoModifier, 0); +} + +WHEN("^I press calculate") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Return, Qt::NoModifier, 0); +} + +WHEN("^I press clear") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Escape, Qt::NoModifier, 0); +} + +WHEN("^I press subtract") { + cucumber::ScenarioScope calculator; + QTest::keyClick(calculator.get(), Qt::Key_Minus, Qt::NoModifier, 0); +} + +THEN("^the display should be empty$") { + cucumber::ScenarioScope calculator; + QCOMPARE(calculator->display().size(), 0); +} + +THEN("^the display should show (.*)$") { + REGEX_PARAM(QString, expected); + cucumber::ScenarioScope calculator; + QCOMPARE(calculator->display(), expected); +} 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..0e380b4d --- /dev/null +++ b/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp @@ -0,0 +1,39 @@ +#ifndef CUKE_QTTESTDRIVER_HPP_ +#define CUKE_QTTESTDRIVER_HPP_ + +#include "../step/StepManager.hpp" +#include + +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 + +class QtTestObject: public QObject { + Q_OBJECT +public: + QtTestObject(QtTestStep* qtTestStep): step(qtTestStep) {} + virtual ~QtTestObject() {} + +protected: + QtTestStep* step; + +private slots: + void test() const { + step->body(); + } +}; + +} +} + +#endif /* CUKE_QTTESTDRIVER_HPP_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f54a02b..9c2d0034 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,6 +15,13 @@ set(CUKE_SOURCES connectors/wire/WireProtocolCommands.cpp ) +if(QT5_FOUND) + qt5_wrap_cpp(MOC_FILE ../include/cucumber-cpp/internal/drivers/QtTestDriver.hpp) + list(APPEND CUKE_SOURCES drivers/QtTestDriver.cpp) + list(APPEND CUKE_SOURCES ${MOC_FILE}) + list(APPEND CUKE_DEP_LIBRARIES ${QT_LIBRARIES}) +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..92afa509 --- /dev/null +++ b/src/drivers/QtTestDriver.cpp @@ -0,0 +1,29 @@ +#include "cucumber-cpp/internal/drivers/QtTestDriver.hpp" + +#include +#include +#include + +namespace cucumber { +namespace internal { + +const InvokeResult QtTestStep::invokeStepBody() { + QTemporaryFile file; + if (!file.open()) { + return InvokeResult::failure("Unable to open temporary file needed for this test"); + } + + QtTestObject testObject(this); + int returnValue = QTest::qExec(&testObject, QStringList() << "test" << "-o" << file.fileName()); + if (returnValue == 0) + return InvokeResult::success(); + else + { + QTextStream ts(&file); + return InvokeResult::failure(ts.readAll().toUtf8().data()); + } +} + +} +} + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a0f2e5f9..b8a04300 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/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 9279fec2..396b8a9c 100755 --- a/travis.sh +++ b/travis.sh @@ -1,6 +1,7 @@ #!/bin/sh set -e #break script on non-zero exitcode from any command set -x #display command being executed + gem install bundler bundle install @@ -19,8 +20,14 @@ cmake --build build cmake --build build --target test cmake --build build --target features +QTTEST=build/examples/Calc/QtTestCalculatorSteps GTEST=build/examples/Calc/GTestCalculatorSteps BOOST=build/examples/Calc/BoostCalculatorSteps +if [ -f $QTTEST ]; then + $QTTEST >/dev/null & + cucumber examples/Calc + wait +fi if [ -f $GTEST ]; then $GTEST >/dev/null & cucumber examples/Calc