diff --git a/.travis.yml b/.travis.yml index 03671369..bd66f8bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ env: global: - DISPLAY=:99 matrix: - - GMOCK_VER=1.8.0 - - GMOCK_VER=1.7.0 + - GMOCK_VER=1.8.0 + - GMOCK_VER=1.7.0 - GMOCK_PATH=/usr/src/gmock #1.6.0 from ubuntu trusty repo matrix: include: @@ -31,14 +31,22 @@ matrix: compiler: clang env: GMOCK_VER=1.7.0 +before_script: + - git clone https://github.com/cgreen-devs/cgreen.git + - git -C cgreen checkout 7030597 + - cmake -E make_directory cgreen/build + - cmake -E chdir cgreen/build cmake -G Ninja -DCMAKE_INSTALL_PREFIX:PATH=${HOME}/usr .. + - cmake --build cgreen/build + - cmake --build cgreen/build --target install + addons: apt: packages: - clang-format-3.8 - - libboost-thread-dev + - libboost-thread-dev - libboost-system-dev - libboost-regex-dev - - libboost-date-time-dev + - libboost-date-time-dev - libboost-filesystem-dev - libboost-program-options-dev - libboost-test-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b71a62e..b86332c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ option(CUKE_USE_STATIC_BOOST "Statically link Boost (except boost::test)" ${W 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_CGREEN "Disable Cgreen 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) @@ -138,6 +139,14 @@ if(NOT CUKE_DISABLE_QT) endif() endif() +# +# cgreen +# + +if(NOT CUKE_DISABLE_CGREEN) + find_package(cgreen) +endif() + # # Valgrind # diff --git a/README.md b/README.md index 143b93d5..dd15cf5f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ It relies on a few libraries: Optional library for Boost Test driver: *test*. * [GTest](http://code.google.com/p/googletest/) 1.6 or later. Optional for the GTest driver. By default downloaded and built by CMake. +* [Cgreen](https://github.com/cgreen-devs/cgreen) builds from master branch since 04/28/2017 or later. + Optional for the Cgreen driver. * [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 and QtTest driver (only Qt 5). @@ -49,7 +51,7 @@ to run the functional test suite. To install the Ruby prerequisites: ``` -gem install bundler +gem install bundler // For windows: gem install bundle bundle install ``` diff --git a/cmake/modules/Findcgreen.cmake b/cmake/modules/Findcgreen.cmake new file mode 100644 index 00000000..4b52a97c --- /dev/null +++ b/cmake/modules/Findcgreen.cmake @@ -0,0 +1,55 @@ +#.rst: +# Findcgreen +# ---------- +# +# Find the cgreen testing framework. +# +# Result variables +# ^^^^^^^^^^^^^^^^ +# +# This module will set the following variables in your project: +# +# ``CGREEN_FOUND`` +# true if the cgreen headers, libraries and executable were found +# ``CGREEN_INCLUDE_DIRS`` +# the directory containing the cgreen headers +# ``CGREEN_LIBRARIES`` +# cgreen libraries to be linked +# ``CGREEN_EXECUTABLE`` +# cgreen executable +# +# Cache variables +# ^^^^^^^^^^^^^^^ +# +# The following cache variables may also be set: +# +# ``CGREEN_INCLUDE_DIR`` +# the directory containing the cgreen headers +# ``CGREEN_LIBRARY`` +# the path to the cgreen library +# ``CGREEN_RUNNER`` +# cgreen-runner executable + +include(FindPackageHandleStandardArgs) + +find_path(CGREEN_INCLUDE_DIR "cgreen/cgreen.h") +find_library(CGREEN_LIBRARY NAMES cgreen libcgreen) +find_program(CGREEN_RUNNER cgreen-runner) +mark_as_advanced(CGREEN_INCLUDE_DIR CGREEN_LIBRARY CGREEN_RUNNER) + +find_package_handle_standard_args(cgreen + REQUIRED_VARS CGREEN_LIBRARY CGREEN_INCLUDE_DIR CGREEN_RUNNER) + +if(CGREEN_FOUND) + add_library(Cgreen::Cgreen UNKNOWN IMPORTED) + set_target_properties(Cgreen::Cgreen PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${CGREEN_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${CGREEN_INCLUDE_DIR}" + ) + add_executable(Cgreen::runner IMPORTED) + set_target_properties(Cgreen::runner PROPERTIES + IMPORTED_LOCATION "${CGREEN_RUNNER}" + ) +endif() + diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 889ca232..3151529c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Calc) add_subdirectory(CalcQt) +add_subdirectory(FizzBuzz) add_subdirectory(FeatureShowcase) diff --git a/examples/Calc/CMakeLists.txt b/examples/Calc/CMakeLists.txt index e0e04c1d..90c77a41 100644 --- a/examples/Calc/CMakeLists.txt +++ b/examples/Calc/CMakeLists.txt @@ -21,6 +21,11 @@ if(Boost_UNIT_TEST_FRAMEWORK_FOUND) target_link_libraries(BoostCalculatorSteps Calc ${CUKE_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) endif() +if(CGREEN_FOUND) + add_executable(CgreenCalculatorSteps features/step_definitions/CgreenCalculatorSteps) + target_link_libraries(CgreenCalculatorSteps Calc ${CUKE_LIBRARIES} Cgreen::Cgreen) +endif() + if(Qt5TEST_FOUND) add_executable(QtTestCalculatorSteps features/step_definitions/QtTestCalculatorSteps) target_link_libraries(QtTestCalculatorSteps Calc Qt5::Test ${CUKE_LIBRARIES}) diff --git a/examples/Calc/features/step_definitions/CgreenCalculatorSteps.cpp b/examples/Calc/features/step_definitions/CgreenCalculatorSteps.cpp new file mode 100644 index 00000000..ab603372 --- /dev/null +++ b/examples/Calc/features/step_definitions/CgreenCalculatorSteps.cpp @@ -0,0 +1,38 @@ +#include // general unit testing +#include // mocking functionality +#include + +#include + +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; + + assert_that_double(expected, is_equal_to_double(context->result)); +} \ No newline at end of file diff --git a/examples/CalcQt/CMakeLists.txt b/examples/CalcQt/CMakeLists.txt index 9388267c..195c169e 100644 --- a/examples/CalcQt/CMakeLists.txt +++ b/examples/CalcQt/CMakeLists.txt @@ -24,4 +24,8 @@ if(QT_LIBRARIES) target_link_libraries(GTestCalculatorQtSteps libcalcqt ${CUKE_LIBRARIES} ${CUKE_GTEST_LIBRARIES} ${QT_LIBRARIES}) endif() + if(CGREEN_FOUND) + add_executable(CgreenCalculatorQtSteps features/step_definitions/CgreenCalculatorQtSteps) + target_link_libraries(CgreenCalculatorQtSteps libcalcqt ${CUKE_LIBRARIES} Cgreen::Cgreen ${QT_LIBRARIES}) + endif() endif() diff --git a/examples/CalcQt/features/step_definitions/CgreenCalculatorQtSteps.cpp b/examples/CalcQt/features/step_definitions/CgreenCalculatorQtSteps.cpp new file mode 100644 index 00000000..a27fceff --- /dev/null +++ b/examples/CalcQt/features/step_definitions/CgreenCalculatorQtSteps.cpp @@ -0,0 +1,75 @@ +#include +#include // general unit testing +#include // mocking functionality +#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; + assert_equal(calculator->display().size(), 0); + QTest::qWait(millisecondsToWait()); +} + +THEN("^the display should show (.*)$") { + REGEX_PARAM(QString, expected); + cucumber::ScenarioScope calculator; + assert_string_equal(expected.toLatin1().data(), calculator->display().toLatin1().data()); + QTest::qWait(millisecondsToWait()); +} diff --git a/examples/FizzBuzz/CMakeLists.txt b/examples/FizzBuzz/CMakeLists.txt new file mode 100644 index 00000000..4013dba8 --- /dev/null +++ b/examples/FizzBuzz/CMakeLists.txt @@ -0,0 +1,10 @@ +project(FizzBuzz) + +include_directories(${CUKE_INCLUDE_DIRS} src) + +add_library(FizzBuzz src/FizzBuzzReporter) + +if(CGREEN_FOUND) + add_executable(FizzBuzzSteps features/step_definitions/FizzBuzzSteps) + target_link_libraries(FizzBuzzSteps FizzBuzz ${CUKE_LIBRARIES} Cgreen::Cgreen) +endif() diff --git a/examples/FizzBuzz/features/FizzBuzz.feature b/examples/FizzBuzz/features/FizzBuzz.feature new file mode 100644 index 00000000..fb6911ff --- /dev/null +++ b/examples/FizzBuzz/features/FizzBuzz.feature @@ -0,0 +1,17 @@ +# language: en + +Feature: fizz_buzz_reporter + In order to practice for programming interviews + As someone who is bad at the FIZZ, BUZZ exercise + I want to be told whether an unsigned integer corresponds to FIZZ, BUZZ, or FIZZBUZZ + + Scenario Outline: Report the FIZZBUZZ string associated with an integer + Given I have passed into fizzBuzzReporter + Then the result should be + + Examples: + | input | output | + | 3 | FIZZ | + | 5 | BUZZ | + | 15 | FIZZBUZZ | + | 11 | 11 | diff --git a/examples/FizzBuzz/features/step_definitions/FizzBuzzSteps.cpp b/examples/FizzBuzz/features/step_definitions/FizzBuzzSteps.cpp new file mode 100644 index 00000000..18e39af1 --- /dev/null +++ b/examples/FizzBuzz/features/step_definitions/FizzBuzzSteps.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include "FizzBuzzReporter.h" + +using cucumber::ScenarioScope; +using namespace cgreen; + +static const size_t REPORT_STRING_LEN = 512; + +struct FizzBuzzState { + char reportBuffer[REPORT_STRING_LEN]; +}; + +// mocked version of printf +int printf(const char *, ...) { + // do nothing + return (int)mock(); +} + +GIVEN("^I have passed (.*) into fizzBuzzReporter") { + REGEX_PARAM(unsigned int, input); + + ScenarioScope context; + + // expect mocked function to be called + expect(printf); + + fizzBuzzReporter(input, context->reportBuffer, REPORT_STRING_LEN); +} + +THEN("^the result should be (.*)$") { + + REGEX_PARAM(std::string, expected); + + ScenarioScope context; + + assert_that(context->reportBuffer, is_equal_to_string(expected.c_str())); +} diff --git a/examples/FizzBuzz/features/step_definitions/cucumber.wire b/examples/FizzBuzz/features/step_definitions/cucumber.wire new file mode 100644 index 00000000..da2da560 --- /dev/null +++ b/examples/FizzBuzz/features/step_definitions/cucumber.wire @@ -0,0 +1,2 @@ +host: localhost +port: 3902 diff --git a/examples/FizzBuzz/features/support/env.rb b/examples/FizzBuzz/features/support/env.rb new file mode 100644 index 00000000..e69de29b diff --git a/examples/FizzBuzz/src/FizzBuzzReporter.c b/examples/FizzBuzz/src/FizzBuzzReporter.c new file mode 100644 index 00000000..ca451679 --- /dev/null +++ b/examples/FizzBuzz/src/FizzBuzzReporter.c @@ -0,0 +1,22 @@ +#include + +#include "FizzBuzzReporter.h" + +/* + * Written as an example of a C program we want to test. + */ + +// printf included to provide and example of how to mock with cgreen +void fizzBuzzReporter(const unsigned int input, char* const reportBuffer, const size_t bufferSize) { + if((input % 15) == 0) { + snprintf(reportBuffer, bufferSize, "FIZZBUZZ"); + } else if((input % 3) == 0) { + snprintf(reportBuffer, bufferSize, "FIZZ"); + } else if((input % 5) == 0) { + snprintf(reportBuffer, bufferSize, "BUZZ"); + } else { + snprintf(reportBuffer, bufferSize, "%u", input); + } + + printf("%u reports %s\n", input, reportBuffer); +} diff --git a/examples/FizzBuzz/src/FizzBuzzReporter.h b/examples/FizzBuzz/src/FizzBuzzReporter.h new file mode 100644 index 00000000..28404350 --- /dev/null +++ b/examples/FizzBuzz/src/FizzBuzzReporter.h @@ -0,0 +1,16 @@ +#ifndef CUKE_FIZZBUZZREPORTER_H_ +#define CUKE_FIZZBUZZREPORTER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void fizzBuzzReporter(unsigned int input, char * reportBuffer, size_t bufferSize); + +#ifdef __cplusplus +} +#endif + +#endif // CUKE_FIZZBUZZREPORTER_H_ \ No newline at end of file diff --git a/include/cucumber-cpp/internal/drivers/CgreenDriver.hpp b/include/cucumber-cpp/internal/drivers/CgreenDriver.hpp new file mode 100644 index 00000000..6febe556 --- /dev/null +++ b/include/cucumber-cpp/internal/drivers/CgreenDriver.hpp @@ -0,0 +1,38 @@ +#ifndef CUKE_CGREENDRIVER_HPP_ +#define CUKE_CGREENDRIVER_HPP_ + +#include + +#include "../step/StepManager.hpp" + +using namespace cgreen; + +namespace cucumber { +namespace internal { + + +class CukeCgreenInterceptor; + +typedef int TextPrinter(const char *format, ...); + +typedef struct { + TextPrinter* printer; + int depth; +} TextMemo; + +class CgreenStep : public BasicStep { +protected: + const InvokeResult invokeStepBody(); + static bool initialized; + +private: + void initCgreenTest(); + void setReporterPrinter(TestReporter*, TextPrinter*); +}; + +#define STEP_INHERITANCE(step_name) ::cucumber::internal::CgreenStep + +} // namespace internal +} // namespace cucumber + +#endif // CUKE_CGREENDRIVER_HPP_ diff --git a/include/cucumber-cpp/internal/drivers/DriverSelector.hpp b/include/cucumber-cpp/internal/drivers/DriverSelector.hpp index 559be1ab..b75ab236 100644 --- a/include/cucumber-cpp/internal/drivers/DriverSelector.hpp +++ b/include/cucumber-cpp/internal/drivers/DriverSelector.hpp @@ -2,6 +2,8 @@ #include "GTestDriver.hpp" #elif defined(BOOST_TEST_CASE) #include "BoostDriver.hpp" +#elif defined(CGREEN_STRING_COMPARISON_H) + #include "CgreenDriver.hpp" #elif defined(QTEST_H) #include "QtTestDriver.hpp" #endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1430b9db..604d6ed5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,11 @@ if(Boost_UNIT_TEST_FRAMEWORK_FOUND) list(APPEND CUKE_SOURCES drivers/BoostDriver.cpp) endif() +if(CGREEN_FOUND) + list(APPEND CUKE_DEP_LIBRARIES Cgreen::Cgreen) + list(APPEND CUKE_SOURCES drivers/CgreenDriver.cpp) +endif() + if(Qt5TEST_FOUND) qt5_wrap_cpp(MOC_FILE ../include/cucumber-cpp/internal/drivers/QtTestDriver.hpp) list(APPEND CUKE_SOURCES ${MOC_FILE}) diff --git a/src/drivers/CgreenDriver.cpp b/src/drivers/CgreenDriver.cpp new file mode 100644 index 00000000..a1dbe1e1 --- /dev/null +++ b/src/drivers/CgreenDriver.cpp @@ -0,0 +1,163 @@ +#include + +#include +#include + +using namespace cgreen; + +namespace cucumber { +namespace internal { + + +bool CgreenStep::initialized = false; + +static const char* const blacklist[] = { + "Running", + "Completed", + "Failure", + "currentTest", + "\n", + "/" +}; + +class CukeCgreenInterceptor { +private: + std::string cgreenOutput; + bool is_blacklisted(const char* input); + CukeCgreenInterceptor(); + ~CukeCgreenInterceptor(); +public: + static CukeCgreenInterceptor & Instance(); + const std::string & getCgreenOutput(); + void clearCgreenOutput(); + void reset_reporter(); + static int cgreenPrinter(const char* format, ...); + TestSuite *cgreenSuite; + TestReporter *cgreenReporter; + boost::function< void() > currentTestBody; +}; + +Ensure(currentTest) { + if(CukeCgreenInterceptor::Instance().currentTestBody) + { + CukeCgreenInterceptor::Instance().currentTestBody(); + } +} + +CukeCgreenInterceptor::CukeCgreenInterceptor() { + cgreenSuite = NULL; + cgreenReporter = NULL; +} + +CukeCgreenInterceptor::~CukeCgreenInterceptor() { + if(cgreenSuite) { destroy_test_suite(cgreenSuite); } + if(cgreenReporter) { destroy_reporter(cgreenReporter); } +} + +CukeCgreenInterceptor & CukeCgreenInterceptor::Instance() { + static CukeCgreenInterceptor cgreenInterceptor; + return cgreenInterceptor; +} + +const std::string & CukeCgreenInterceptor::getCgreenOutput() { + return cgreenOutput; +} + +void CukeCgreenInterceptor::clearCgreenOutput() { + cgreenOutput.clear(); +} + +void CukeCgreenInterceptor::reset_reporter() { + clearCgreenOutput(); + cgreenReporter->passes = 0; + cgreenReporter->skips = 0; + cgreenReporter->failures = 0; + cgreenReporter->exceptions = 0; +} + +int CukeCgreenInterceptor::cgreenPrinter(const char* format, ...) { + char buffer[10000]; + va_list argPtr; + va_start(argPtr, format); + if(vsnprintf(buffer, sizeof(buffer), format, argPtr) < 0) { + return 0; + } + va_end(argPtr); + + if(!CukeCgreenInterceptor::Instance().is_blacklisted(buffer)) { + CukeCgreenInterceptor::Instance().cgreenOutput += "\n\n"; + CukeCgreenInterceptor::Instance().cgreenOutput += buffer; + CukeCgreenInterceptor::Instance().cgreenOutput += "\n\n"; + } + + static const char blackBoxInfo[] = "\"initCgreenTest\""; + std::size_t position = CukeCgreenInterceptor::Instance().cgreenOutput.find(blackBoxInfo); + if(position != std::string::npos) { + CukeCgreenInterceptor::Instance().cgreenOutput.erase(position); + } + + return CukeCgreenInterceptor::Instance().cgreenOutput.length(); +} + +bool CukeCgreenInterceptor::is_blacklisted(const char* input) { + const int blacklist_size = + sizeof(blacklist) + / sizeof(blacklist[ 0 ]); + + if(input[0] == '\0') { + return true; + } + + for(int idx = 0; idx < blacklist_size; ++idx) { + if(strncmp(input, blacklist[idx], strlen(blacklist[idx])) == 0) { + return true; + } + } + + return false; +} + +void CgreenStep::setReporterPrinter( + TestReporter* reporter, + TextPrinter* newPrinter) { + TextMemo* memo = reinterpret_cast(reporter->memo); + memo->printer = newPrinter; +} + +const InvokeResult CgreenStep::invokeStepBody() { + if(!initialized) { + initCgreenTest(); + } else { + CukeCgreenInterceptor::Instance().reset_reporter(); + } + + CukeCgreenInterceptor::Instance().currentTestBody = boost::bind(&CgreenStep::body, this); + + int suite_result = run_single_test( + CukeCgreenInterceptor::Instance().cgreenSuite, + "currentTest", + CukeCgreenInterceptor::Instance().cgreenReporter); + + if (suite_result == EXIT_SUCCESS) { + return InvokeResult::success(); + } else { + return InvokeResult::failure(CukeCgreenInterceptor::Instance().getCgreenOutput()); + } +} + +void CgreenStep::initCgreenTest() { + CukeCgreenInterceptor::Instance().cgreenSuite = create_test_suite(); + CukeCgreenInterceptor::Instance().cgreenReporter = create_text_reporter(); + CukeCgreenInterceptor::Instance().clearCgreenOutput(); + + setReporterPrinter( + CukeCgreenInterceptor::Instance().cgreenReporter, + CukeCgreenInterceptor::Instance().cgreenPrinter); + + add_test(CukeCgreenInterceptor::Instance().cgreenSuite, currentTest); + + initialized = true; +} + +} // namespace internal +} // namespace cucumber diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 300dac5d..bb8064d9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -48,6 +48,10 @@ if(Boost_UNIT_TEST_FRAMEWORK_FOUND) cuke_add_driver_test(integration/drivers/BoostDriverTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) endif() +if(CGREEN_FOUND) + cuke_add_driver_test(integration/drivers/CgreenDriverTest Cgreen::Cgreen) +endif() + if(Qt5TEST_FOUND) cuke_add_driver_test(integration/drivers/QtTestDriverTest ${QT_LIBRARIES}) endif() diff --git a/tests/integration/drivers/CgreenDriverTest.cpp b/tests/integration/drivers/CgreenDriverTest.cpp new file mode 100644 index 00000000..5c0683ce --- /dev/null +++ b/tests/integration/drivers/CgreenDriverTest.cpp @@ -0,0 +1,62 @@ +#include +#include +#include "../../utils/DriverTestRunner.hpp" + +using namespace cgreen; +using namespace cucumber; +using namespace cucumber::internal; + +THEN(SUCCEED_MATCHER) { + ScenarioScope ctx; + assert_that(true); +} + +THEN(FAIL_MATCHER) { + ScenarioScope ctx; + assert_that(false); +} + +THEN(PENDING_MATCHER_1) { + pending(); +} + +THEN(PENDING_MATCHER_2) { + pending(PENDING_DESCRIPTION); +} + +class CgreenStepDouble : public CgreenStep { +public: + bool isInitialized() { + return CgreenStep::initialized; + } + + const InvokeResult invokeStepBody() { + return CgreenStep::invokeStepBody(); + }; + + void body() {}; +}; + +class CgreenDriverTest : public DriverTest { +public: + virtual void runAllTests() { + stepInvocationInitsCgreenTest(); + DriverTest::runAllTests(); + } +private: + void stepInvocationInitsCgreenTest() { + CgreenStepDouble framework; + expectFalse( + "Framework is not initialized before the first test", + framework.isInitialized()); + framework.invokeStepBody(); + expectTrue( + "Framework is initialized after the first test", + framework.isInitialized()); + } +}; + +int main() { + CgreenDriverTest test; + return test.run(); +} diff --git a/travis.sh b/travis.sh index cc139602..1046435e 100755 --- a/travis.sh +++ b/travis.sh @@ -2,47 +2,6 @@ set -e #break script on non-zero exitcode from any command set -x #display command being executed -startXvfb () { -# Xvfb sends SIGUSR1 to its parent when it finished startup, this causes the 'wait' below to stop waiting -# Starting Xvfb hangs on OSX, that's why we do this on Linux only now - if [[ "${TRAVIS_OS_NAME}" = "linux" ]]; then - trap : USR1 - (trap '' USR1; Xvfb $DISPLAY -screen 0 640x480x8 -nolisten tcp > /dev/null 2>&1) & - XVFBPID=$! - wait || : - trap '' USR1 - if ! kill -0 $XVFBPID 2> /dev/null; then - echo "Xvfb failed to start" >&2 - exit 1 - fi - else - sudo Xvfb $DISPLAY -screen 0 640x480x8 -nolisten tcp > /dev/null 2>&1 & - XVFBPID=$! - sleep 5 - fi -} - -killXvfb () { - if [ -n "${XVFBPID:-}" ]; then - # Stop virtual X display server - sudo kill $XVFBPID - wait - fi -} - -if [ -n "${FORMAT:-}" ]; then - # Reformat all code changed since this branch forked from the default branch - git fetch origin HEAD - if [ "${TRAVIS_PULL_REQUEST:-false}" = "false" ]; then - BASE_HEAD="$(git rev-parse FETCH_HEAD)" - else - BASE_HEAD="$(git merge-base FETCH_HEAD HEAD)" - fi - git clang-format-3.8 --binary=/usr/bin/clang-format-3.8 --style=file --commit="${BASE_HEAD}" - # Assert that all changes adhere to the asked for style - exec git diff --exit-code -fi - CTEST_OUTPUT_ON_FAILURE=ON export CTEST_OUTPUT_ON_FAILURE @@ -68,12 +27,31 @@ cmake --build build cmake --build build --target test cmake --build build --target features -startXvfb # Start virtual X display server +# Start virtual X display server + +# Starting Xvfb hangs on OSX, that's why we do this on Linux only now +if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + DISPLAY=:99 + export DISPLAY + + # Xvfb sends SIGUSR1 to its parent when it finished startup, this causes the 'wait' below to stop waiting + trap : USR1 + (trap '' USR1; Xvfb $DISPLAY -screen 0 640x480x8 -nolisten tcp > /dev/null 2>&1) & + XVFBPID=$! + wait || : + trap '' USR1 + if ! kill -0 $XVFBPID 2> /dev/null; then + echo "Xvfb failed to start" >&2 + exit 1 + fi +else + unset DISPLAY +fi for TEST in \ build/examples/Calc/GTestCalculatorSteps \ - build/examples/Calc/QtTestCalculatorSteps \ build/examples/Calc/BoostCalculatorSteps \ + build/examples/Calc/CgreenCalculatorSteps \ build/examples/Calc/FuncArgsCalculatorSteps \ ; do if [ -f "${TEST}" ]; then @@ -86,8 +64,8 @@ done for TEST in \ build/examples/CalcQt/GTestCalculatorQtSteps \ - build/examples/CalcQt/QtTestCalculatorQtSteps \ build/examples/CalcQt/BoostCalculatorQtSteps \ + build/examples/CalcQt/CgreenCalculatorQtSteps \ ; do if [ -f "${TEST}" -a -n "${DISPLAY:-}" ]; then "${TEST}" 2> /dev/null & @@ -97,6 +75,17 @@ for TEST in \ fi done +for TEST in \ + build/examples/FizzBuzz/FizzBuzzSteps \ +; do + if [ -f "${TEST}" ]; then + "${TEST}" > /dev/null & + sleep 1 + cucumber examples/FizzBuzz + wait % + fi +done + # Test unix sockets SOCK=cucumber.wire.sock TEST=build/examples/FeatureShowcase/FeatureShowcaseSteps @@ -107,4 +96,8 @@ if [ -f "${TEST}" ]; then wait % fi -killXvfb +if [ -n "${XVFBPID:-}" ]; then + # Stop virtual X display server + kill $XVFBPID + wait +fi