Skip to content

Instantly share code, notes, and snippets.

@paoloambrosio
Created April 4, 2012 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paoloambrosio/2303589 to your computer and use it in GitHub Desktop.
Save paoloambrosio/2303589 to your computer and use it in GitHub Desktop.
CukeBins test for dynamic load of step definitions
On Windows it should use LoadLibrary. This is a sample run on OSX:
$ ./cukebins libsteps*.dylib
--- LOADING ---
libsteps1.dylib
libsteps2.dylib
libsteps3.dylib
--- RUNNING ---
Invoked STEP 1A
Invoked STEP 2A
Invoked STEP 2B
Invoked STEP 3A
Invoked STEP 3B
Invoked STEP 3C
#include "cb.hpp"
#include <iostream>
int register_step(std::string msg) {
std::cout << "Static initialized for " << msg << std::endl;
return 1;
}
#ifndef _CB_
#define _CB_
#include "core.hpp"
#include <string>
#include <memory> // auto_ptr
#include <vector>
#include <boost/shared_ptr.hpp> // ctx
#include <boost/weak_ptr.hpp> // ctx
/* REGISTRATION */
#define STEP_NAME \
BOOST_JOIN(Step, __LINE__)
#define STEP(str) \
_STEP(STEP_NAME, str)
#define _STEP(name, str) \
class name { \
public: \
void body(); \
private: \
static const std::auto_ptr<const StepInfo> x; \
}; \
const std::auto_ptr<const StepInfo> name ::x = std::auto_ptr<const StepInfo>(register_step< name >(str)); \
void name ::body() \
/**/
namespace { // Without this the template would be in common between the steps
template<class T>
class StepInfoImpl : public StepInfo {
public:
void runStepBody() const {
T t;
t.body();
}
};
}
template<class T>
static const StepInfo *register_step(const char *desc) {
const StepInfo *impl = new StepInfoImpl<T>();
ObjectFactory::getCukeEngine()->addStepInfo(impl);
return impl;
}
/* CONTEXT */
namespace {
typedef std::vector<boost::shared_ptr<void> > contexts_type;
class ContextManager {
public:
void purgeContexts();
template<class T> boost::weak_ptr<T> addContext();
protected:
static contexts_type contexts;
};
template<class T>
boost::weak_ptr<T> ContextManager::addContext() {
boost::shared_ptr<T> shared(new T);
contexts.push_back(shared);
return boost::weak_ptr<T> (shared);
}
}
template<class T>
class SomeScope {
public:
SomeScope();
T& operator*();
T* operator->();
private:
ContextManager contextManager;
boost::shared_ptr<T> context;
static boost::weak_ptr<T> contextReference;
};
template<class T>
boost::weak_ptr<T> SomeScope<T>::contextReference;
template<class T>
SomeScope<T>::SomeScope() {
if (contextReference.expired()) {
contextReference = contextManager.addContext<T> ();
}
context = contextReference.lock();
}
template<class T>
T& SomeScope<T>::operator*() {
return *(context.get());
}
template<class T>
T* SomeScope<T>::operator->() {
return (context.get());
}
#endif // _CB_
cmake_minimum_required(VERSION 2.6)
find_package(Boost)
include_directories(${Boost_INCLUDE_DIRS})
find_library(DYNAMIC_LOAD_LIBRARY dl)
add_library(cukebins-core SHARED core.cpp)
add_executable(cukebins main.cpp)
target_link_libraries(cukebins cukebins-core ${DYNAMIC_LOAD_LIBRARY})
add_library(steps1 SHARED steps1.cpp)
target_link_libraries(steps1 cukebins-core)
add_library(steps2 SHARED steps2.cpp)
target_link_libraries(steps2 cukebins-core)
add_library(steps3 SHARED steps3.cpp)
target_link_libraries(steps3 cukebins-core)
#include "core.hpp"
#include <vector>
class CukeEngineImpl : public CukeEngine {
private:
typedef std::vector<const StepInfo *> steps_type;
steps_type steps;
public:
void addStepInfo(const StepInfo *);
void runSteps();
};
void CukeEngineImpl::addStepInfo(const StepInfo *si) {
steps.push_back(si);
}
void CukeEngineImpl::runSteps() {
for(steps_type::const_iterator i = steps.begin(); i != steps.end(); ++i) {
const StepInfo * si = (*i);
si->runStepBody();
}
}
CukeEngine *ObjectFactory::getCukeEngine() {
static CukeEngineImpl cukeEngine;
return &cukeEngine;
}
#ifndef _CORE_
#define _CORE_
class StepInfo {
public:
virtual void runStepBody() const = 0;
};
class CukeEngine {
public:
virtual void addStepInfo(const StepInfo *) = 0;
virtual void runSteps() = 0;
};
class ObjectFactory {
public:
static CukeEngine *getCukeEngine();
};
#endif // _CORE_
#include "core.hpp"
#include <iostream>
#include <dlfcn.h>
int main(int argc, char **argv) {
std::cout << "--- LOADING ---" << std::endl;
for (int i=1; i<argc; ++i) {
std::cout << argv[i] << std::endl;
dlopen(argv[i], RTLD_LAZY);
}
std::cout << "--- RUNNING ---" << std::endl;
ObjectFactory::getCukeEngine()->runSteps();
}
#ifndef _STEPCTX_
#define _STEPCTX_
class CommonContext {
public:
int i;
};
#endif // _STEPCTX_
#include "cb.hpp"
#include "stepctx.hpp"
#include <iostream>
STEP("step1a") {
SomeScope<CommonContext> c;
std::cout << "Invoked STEP 1A c" << ++(c->i) << std::endl;
}
#include "cb.hpp"
#include "stepctx.hpp"
#include <iostream>
namespace {
class LocalContext {
public:
int i;
};
}
STEP("step2a") {
SomeScope<LocalContext> l;
std::cout << "Invoked STEP 2A l" << ++(l->i) << std::endl;
}
STEP("step2b") {
SomeScope<CommonContext> c;
std::cout << "Invoked STEP 2B c" << ++(c->i) << std::endl;
}
#include "cb.hpp"
#include <iostream>
namespace {
class LocalContext {
public:
int i;
};
}
STEP("step3a") {
std::cout << "Invoked STEP 3A" << std::endl;
}
STEP("step3b") {
std::cout << "Invoked STEP 3B" << std::endl;
}
STEP("step3c") {
SomeScope<LocalContext> l;
std::cout << "Invoked STEP 3C l" << ++(l->i) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment