cucumber / cucumber-cpp Goto Github PK
View Code? Open in Web Editor NEWSupport for writing Cucumber step definitions in C++
License: MIT License
Support for writing Cucumber step definitions in C++
License: MIT License
Implement passing tables to a step as documented in the Tables section.
See "Multiline Table Arguments" on https://github.com/aslakhellesoy/cucumber/blob/master/legacy_features/wire_protocol.feature
Cucumber Wire Protocol scenario “Step matches returns details about the remote step definition”
Take a look at the Cucumber TCK and Cucumber-JS for how to implement them!
They should test every test driver (and later every connector?)
Handle registration of pending steps and the reply to Cucumber
Hello,
I’m trying to install cucumber-cpp in order to execute some tests and evaluate the framework.
For this, I use the building steps indicated in https://github.com/cucumber/cucumber-cpp, that is:
cmake -E make_directory build
cmake -E chdir build cmake -Dgtest_build_samples=ON -DCPPSPEC_LIBRARY=/cygdrive/d/PortableApps/cppspec-master/build/src/libCppSpec.dll.a -DCPPSPEC_INCLUDE_DIR=/cygdrive/d/PortableApps/cppspec-master/include/ -DGTEST_LIBRARY=/cygdrive/d/PortableApps/gmock-1.6.0/gtest/lib/.libs/libgtest.a -DGTEST_MAIN_LIBRARY=/cygdrive/d/PortableApps/gmock-1.6.0/gtest/lib/.libs/libgtest_main.a -DGTEST_INCLUDE_DIR=/cygdrive/d/PortableApps/gmock-1.6.0/gtest/include/ -DGMOCK_LIBRARY=/cygdrive/d/PortableApps/gmock-1.6.0/lib/.libs/libgmock.a -DGMOCK_INCLUDE_DIR=/cygdrive/d/PortableApps/gmock-1.6.0/include/ -DGMOCK_MAIN_LIBRARY=/cygdrive/d/PortableApps/gmock-1.6.0/lib/.libs/libgmock_main.a ..
cmake --build build
cmake --build build --target test
Thus, the building process seems to be right, but on the other hand no cucumber.exe file is generated!!, I don't understand what's going on. Could anyone help me please?
NOTE: I'm using CYGWIN environment and the following library versions:
- Boost 1.48
- GTest 1.6
- GMock 1.6
Many thanks in advance.
Best regards!
With all the major components in place, the code should be refactored and documented.
The use of templates should be reduced to speed up compilation building static libraries to be linked.
The code should be unit-tested with mocks.
Const and references should be used where it makes sense (methods and for their input and output parameters).
Handle snippet text requests from Cucumber. See "Wire server returns snippets for a step that didn't match" scenario on the wire server feature file.
Add FindGTest.cmake from CMake 2.8 and add the modules dir if version <2.8.
Test CukeBins with GTest 1.3 and previous versions of Boost.
Support other test frameworks for defining and running steps. Feel free to contribute! ;-)
We should add logging. It's almost impossible to understand what is going on behind the scenes, thus tracking any misbehavior.
We don't need a full-featured logger like Boost.Log or Google Glog. We need a simple class to track what is going on, if instructed to.
CukeBins should (auto)register the steps itself instead of saving some information and rely on the testing framework for everything else.
I was trying to add some cleanup/validation at the end of each scenario for validating GMock expectations.
At first, we were doing this in the ~Context(), but GTest assertions cause the CukeBin to crash. Therefore, I found you have the hook macros, and the AFTER() hook is exactly what I need. Unfortunately the AFTER hook is being executed at the start of the NEXT scenario, instead of at the end of the desired one. ALSO, an extra empty scenario is being executed at the end of the suite execution (likely because the AFTER hook is being registered in the wrong place).
Unfortunately, on debugging with some print statements, I see:
Creating wire file with port=43683 at '/features/step_definitions/cucumber.wire'
............
4 scenarios (4 passed)
12 steps (12 passed)
0m2.619s
Cuke test passed! (see file://home/greg/GSD/qtcreator-build/_AcceptanceTestOutput/LightingAppFeatures-report.html)
Context()
BEFORE: spy_valid=0
STEP ^front worklights are (installed|not installed)$: spy_valid=0
AFTER_STEP: spy_valid=0
STEP ^front worklights should be (shown|hidden)$: spy_valid=0
AFTER_STEP: spy_valid=1
STEP ^front worklights get (installed|uninstalled)$: spy_valid=1
AFTER_STEP: spy_valid=1
~Context()
Context()
AFTER: spy_valid=0
This is where we need to validate mock expectations, but sequence is incorrect!
BEFORE: spy_valid=0
STEP ^front worklights are (installed|not installed)$: spy_valid=0
AFTER_STEP: spy_valid=0
STEP ^front worklights should be (shown|hidden)$: spy_valid=0
AFTER_STEP: spy_valid=1
STEP ^front worklights get (installed|uninstalled)$: spy_valid=1
AFTER_STEP: spy_valid=1
~Context()
Context()
AFTER: spy_valid=0
This is where we need to validate mock expectations, but sequence is incorrect!
BEFORE: spy_valid=0
STEP ^front worklights are (on|off)$: spy_valid=0
AFTER_STEP: spy_valid=0
STEP ^front worklights should be (on|off)$: spy_valid=0
AFTER_STEP: spy_valid=1
STEP ^front worklights get turned (on|off)$: spy_valid=1
AFTER_STEP: spy_valid=1
~Context()
Context()
AFTER: spy_valid=0
This is where we need to validate mock expectations, but sequence is incorrect!
BEFORE: spy_valid=0
STEP ^front worklights are (on|off)$: spy_valid=0
AFTER_STEP: spy_valid=0
STEP ^front worklights should be (on|off)$: spy_valid=0
AFTER_STEP: spy_valid=1
STEP ^front worklights get turned (on|off)$: spy_valid=1
AFTER_STEP: spy_valid=1
~Context()
Context() <<<< Extra Context created, JUST to execute AFTER step!!!
AFTER: spy_valid=0
This is where we need to validate mock expectations, but sequence is incorrect!
~Context()
[100%] Built target RunLightingAppFeatures
Step match should return the native regular expression used to match the step:
["success",[{"id":"1", "args":[], "source":"MyApp.MyClass:123", "regexp":"we.*"}]]
Implement a connector for Cucumber in Ruby and for the JVM to call the C++ steps without using the wire protocol, but defining a new language.
Use GMock 1.5 or GTest 1.6 (that should include matchers when it's released)
Support Boost Test Library as a test framework for defining and running steps
Write a driver for CppUTest
In case one passes a string parameter with containing spaces from cucumber to the SUT, the string parameter is cut after the first blank. So in my example below I just get the value “Coronis” and not the complete string.
But by adding into CukeCommand.hpp:56
template<>
std::string fromString(const std::string& s)
{
return s;
}
This works fine. Do you think this is the correct way of doing it or rely other parts of the framework on this template and expect a different behaviour?
We should have a continuous integration server to compile and test the software under several operating systems. Issues like #38 would be prevented this way.
Use CPack to define installation targets
Add driver for Igloo - BDD style unit testing in C++
Super minor one:
The readme lists which Boost libraries are required, but the list does not include Boost Spirit. Since JSON Spirit depends on Boost Spirit, I'd assume that it should be listed in the readme, too.
Hi, I am trying to build the example test for x64 settings, and ran into couple "unresolved external symbol" when building BoostCalculatorSteps project. Does anyone knows what is going on?? It works fine for 32-bits settings.
Setup:
Note:
BoostCalculatorSteps project --
4>------ Rebuild All started: Project: BoostCalculatorSteps, Configuration: Debug x64 ------
4>Build started 10/26/2012 1:27:15 PM.
4>_PrepareForClean:
4> Deleting file "BoostCalculatorSteps.dir\Debug\BoostCalculatorSteps.lastbuildstate".
4>InitializeBuildStatus:
4> Touching "BoostCalculatorSteps.dir\Debug\BoostCalculatorSteps.unsuccessfulbuild".
4>CustomBuild:
4> Building Custom Rule D:/git/cucumber-cpp/examples/Calc/CMakeLists.txt
4> CMake does not need to re-run because D:\git\cucumber-cpp\build64\examples\Calc\CMakeFiles\generate.stamp is up-to-date.
4>ClCompile:
4> BoostCalculatorSteps.cpp
4>d:\git\cucumber-cpp\include\cucumber-cpp\internal\step../Table.hpp(21): warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
4>d:\git\cucumber-cpp\include\cucumber-cpp\internal\step../Table.hpp(22): warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
4>cucumber-cpp.lib(main.obj) : error LNK2019: unresolved external symbol "class boost::system::error_category const & __cdecl boost::system::system_category(void)" (?system_category@system@boost@@YAAEBVerror_category@12@XZ) referenced in function "public: __cdecl boost::system::error_code::error_code(void)" (??0error_code@system@boost@@qeaa@XZ)
4>cucumber-cpp.lib(WireServer.obj) : error LNK2001: unresolved external symbol "class boost::system::error_category const & __cdecl boost::system::system_category(void)" (?system_category@system@boost@@YAAEBVerror_category@12@XZ)
4>cucumber-cpp.lib(main.obj) : error LNK2019: unresolved external symbol "class boost::system::error_category const & __cdecl boost::system::generic_category(void)" (?generic_category@system@boost@@YAAEBVerror_category@12@XZ) referenced in function "void __cdecl boost::system::`dynamic initializer for 'posix_category''(void)" (??__Eposix_category@system@boost@@yaxxz)
4>cucumber-cpp.lib(WireServer.obj) : error LNK2001: unresolved external symbol "class boost::system::error_category const & __cdecl boost::system::generic_category(void)" (?generic_category@system@boost@@YAAEBVerror_category@12@XZ)
4>D:\git\cucumber-cpp\build64\examples\Calc\Debug\BoostCalculatorSteps.exe : fatal error LNK1120: 2 unresolved externals
4>
4>Build FAILED.
4>
4>Time Elapsed 00:00:01.76
========== Rebuild All: 3 succeeded, 1 failed, 0 skipped ==========
I have a UTF8 encoded features definition file:
# language: en
Feature:
...
Scenario Outline:
... step defs ...
Examples:
|sth|sth|expected_value|
|...|...|Dąślężynów,Oslo,Stockholm|
I'm using cukebins with gtest. I want to compare some UTF8 encoded text with the string extracted from 'expected_value' collumn. The problem is that when extracting the text from 'expected_value' with:
REGEX_PARAM(std::string, expected_value);
I get 'D��l�żynów'.
After digging through cukebins code I managed to get closer to the problem's source.
Here is log of what cucumber is sending and recieving around the moment when the problem appears:
...
cucumber-send:
["step_matches",{"name_to_match":"the labels are present on the tile Dąślężynów,Oslo,Stockholm"}]
cucumber-raw_response:
["success",[{"args":[{"pos":35,"val":"D\u00C4\u0085\u00C5\u009Bl\u00C4\u0099\u00C5\u00BCyn\u00C3\u00B3w,Oslo,Stockholm"}],"id":"7","source":"test_steps.cpp:76"}]]
cucumber-send:
["invoke",{"id":"7","args":["D��l�żynów,Oslo,Stockholm"]}]
...
Anyway, found an ugly way to workaround the issue, doesn't seem to break anything - I switched off part of character escaping when json_spirit writes response to stream:
File json_spirit_writer_template.h:
template< class String_type >
String_type add_esc_chars( const String_type& s )
{
typedef typename String_type::const_iterator Iter_type;
typedef typename String_type::value_type Char_type;
String_type result;
const Iter_type end( s.end() );
for( Iter_type i = s.begin(); i != end; ++i )
{
const Char_type c( *i );
if( add_esc_char( c, result ) ) continue;
const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
// This is commented out due to LBSR-2427 - issue with unicode national chars.
// if( iswprint( unsigned_c ) )
// {
result += c;
// }
// else
// {
// result += non_printable_to_string< String_type >( unsigned_c );
// }
}
return result;
}
OS: 64-bit Ubuntu Linux. Same problem appeared on 2 machines.
Inside WireServer.hpp the SocketServer c'tor takes a (signed) short as parameter. This must be an unsigned short, as no negative ports are allowed and the boost implementation would like to get a unsigned short as well as parameter.
On Boost 1.40...
src/drivers/BoostDriver.cpp: In member function ‘void cukebins::internal::BoostStep::initBoostTest()’:
src/drivers/BoostDriver.cpp:85: error: cannot allocate an object of abstract type ‘cukebins::internal::CukeBoostLogInterceptor’
src/drivers/BoostDriver.cpp:28: note: because the following virtual functions are pure within ‘cukebins::internal::CukeBoostLogInterceptor’:
/usr/include/boost/test/unit_test_log_formatter.hpp:99: note: virtual void boost::unit_test::unit_test_log_formatter::log_exception(std::ostream&, const boost::unit_test::log_checkpoint_data&, boost::unit_test::const_string)
make[2]: *** [src/CMakeFiles/CukeBins.dir/drivers/BoostDriver.cpp.o] Error 1
make[1]: *** [src/CMakeFiles/CukeBins.dir/all] Error 2
make: *** [all] Error 2
The definition of steps in multiple source files fails, when two steps are in the same line of different source files.
Then two objects with the same name are generated and the linking fails.
Use CPack to create package/installers for different platforms.
The failure message has to be sent back to cucumber for printing:
["fail",{"message":"The wires are down", "exception":"Some.Foreign.ExceptionType"}]
It will be printed like this:
The wires are down (Some.Foreign.ExceptionType from localhost:54321)
features/wired.feature:3:in `Given we're all wired'
Hi,
I'm getting one crash while running the tests:
The following tests FAILED: 37 - WireMessageCodecTest.handlesStepMatchesResponse (SEGFAULT)
I think this comes from a side effect of BOOST_FOREACH and temporaries.
If you write instead of line 286 in WireProcol.cpp:
const std::vector<StepMatch> matchingSteps = response->getMatchingSteps(); BOOST_FOREACH(StepMatch m, matchingSteps) {
... the problem will go away (you can also return a reference rather than a copy in getMatchingSteps to avoid the temporary).
There is certainly a better fix and I leave you the choice (I personally prefer returning const references rather than copies but there are tradeoffs, also in the code above I don't like using the internal collection type: std::vector<StepMatch>
).
This is on LinuxMint 13/X86_64 but I think the problem is more general than this specific OS.
$ dpkg -s libboost-dev | grep 'Version' Version: 1.48.0.2
Regards,
Stephane.
`Program received signal SIGSEGV, Segmentation fault.
0x00007ffff753ef2b in std::basic_string<char, std::char_traits, std::allocator >::basic_string(std::string const&) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) up
#1 0x000000000058bf26 in cucumber::internal::StepMatch::StepMatch (
this=0x7fffffffde60)
at (...)cucumber-cpp/include/cucumber-cpp/internal/connectors/wire/../../CukeEngine.hpp:18
18 class StepMatch {
(gdb) up
#2 0x00000000005cdd1e in cucumber::internal::(anonymous namespace)::WireResponseEncoder::visit (this=0x7fffffffe250, response=0x7fffffffe300)
at (...)/cucumber-cpp/src/connectors/wire/WireProtocol.cpp:286
286 BOOST_FOREACH(StepMatch m, response->getMatchingSteps())`
Implement support for tagged Cucumber hooks
Using the following CUKE_CONTEXT the destructor will not be called if the scenario fails. It will be called if the scenario succeeds.
CUKE_CONTEXT (TestContext)
{
TestContext () {
printf ("setup context\n");
}
~TestContext () {
printf ("teardown context\n");
}
};
X:\cukebins>cmake --build build --target test
Running tests...
Test project X:/cukebins/build
[...]
92% tests passed, 2 tests failed out of 26
Total Test time (real) = 9.73 sec
The following tests FAILED:
8 - SocketServerTest.exitsOnFirstConnectionClosed (Failed)
9 - SocketServerTest.receiveAndSendsSingleLineMassages (Failed)
Errors while running CTest
NMAKE : fatal error U1077: '"C:\Program Files\CMake 2.8\bin\ctest.exe"' : return code '0x8'
Stop.
X:\cukebins>build\tests\WireServerTest.exe --gtest_filter=SocketServerTest.exitsOnFirstConnectionClosed
Running main() from gtest_main.cc
Note: Google Test filter = SocketServerTest.exitsOnFirstConnectionClosed
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from SocketServerTest
[ RUN ] SocketServerTest.exitsOnFirstConnectionClosed
X:\cukebins\tests\integration\WireServerTest.cpp(67): error: Value of: serverThread.joinable()
Actual: true
Expected: false
[ FAILED ] SocketServerTest.exitsOnFirstConnectionClosed (4031 ms)
[----------] 1 test from SocketServerTest (4031 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4031 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] SocketServerTest.exitsOnFirstConnectionClosed
1 FAILED TEST
X:\cukebins>build\tests\WireServerTest.exe --gtest_filter=SocketServerTest.receiveAndSendsSingleLineMassages
Running main() from gtest_main.cc
Note: Google Test filter = SocketServerTest.receiveAndSendsSingleLineMassages
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from SocketServerTest
[ RUN ] SocketServerTest.receiveAndSendsSingleLineMassages
X:\cukebins\tests\integration\WireServerTest.cpp(79): error: Value of: response
Actual: ""
Expected: request
Which is: "Echo"
X:\cukebins\tests\integration\WireServerTest.cpp(83): error: Value of: serverThread.joinable()
Actual: true
Expected: false
[ FAILED ] SocketServerTest.receiveAndSendsSingleLineMassages (4516 ms)
[----------] 1 test from SocketServerTest (4531 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (4547 ms total)
[ PASSED ] 0 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] SocketServerTest.receiveAndSendsSingleLineMassages
1 FAILED TEST
GTest cannot test itself. Use a custom program returning the correct exit code to be used with CTest.
Replacing the line /src/drivers/BoostDriver.cpp:56 which is
description.clear();
with
description.str("");
seems to fix the problem.
This StackOverflow question is related: http://stackoverflow.com/questions/20731/in-c-how-do-you-clear-a-stringstream-variable
Implement passing tables to a step as documented in the Diffing tables section.
Wire server should be (optionally) precompiled, and not be a header-only library.
Allow Cucumber-Cpp to execute features directly using the Gherkin parser without relying on Cucumber-Ruby.
Support CppSpec as a test framework for defining and running steps
Remove USING_CONTEXT macro and introduce scenario scope template, and perhaps a global scope. Example:
// Created on first use in every scenario, destroyed when the scenario ends
ScenarioScope<Ark> ark;
// Created on first use, destroyed on close
GlobalScope<MyClass> myClassPointer;
It might be possible to compile and link step definition files to separate dynamic libraries, and load them selectively: https://gist.github.com/2303589
This will bring a better overall experience. Executing Cucumber-Cpp should be something like:
$ cucumber-cpp --tags mytag --glue libsteps1.so --glue libsteps2.so --format progress features/some.feature
----................
4 scenarios (4 passed)
16 steps (16 passed)
0m0.039s
$
It will start a wire server, load steps libraries, and run Cucumber. Every command line argument that is not understood by Cucumber-Cpp (--glue/-g) will be passed down to Cucumber. It might even autoconfigure the port by writing the wire file and adding it to the step_definitions while calling the Cucumber command line.
Edit: clarified that it's about dynamic libraries and not executing scenarios
Write user documentation including an introductory guide, hooks (random execution order), contexts, and any other feature.
Edit: reworded and got rid of what was done as part of other tickets
Implement support for Cucumber hooks except for tag handling
Write a full documentation for this release including an introductory guide and a list of changed and new features. Check id the README.txt is in sync.
The googletest driver might be better implemented with a logger, instead of by catching the exceptions.
Duplicate of paoloambrosio/cukebins#29
GIVEN("^(.*) is logged in$") {
REGEX_PARAM(string, username);
given("the user "+username+" exists");
given("I log in as "+username);
}
GIVEN("^the user (.*) exists$") {
//...
}
GIVEN("^I log in as (.*)$") {
//...
}
https://github.com/aslakhellesoy/cucumber/wiki/Calling-Steps-from-Step-Definitions
We should be able to accept numbers as 1.200,34 or 1,200.34 depending on the language.
...anything else?
Now that the library is compiled it should be possible to implement several wire server implementations (as one using QT core).
The software should be refactored to allow easy testing of GUIs.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.