/* * Copyright 2007, 2008 Timo Puronen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SPECIFICATION_H_ #define SPECIFICATION_H_ #include "SpecificationBase.h" #include "Reporter.h" #include "ShouldType.h" #include "ContextHolder.h" #include /** * MSVC++ does not support not keyword. */ #ifdef _WIN32 #define not ! #endif namespace CppSpec { /** * Specification base class. * @param Context the class under test. * @param Derived the concrete specification class as in curiously recurring template pattern. */ template class Specification : public SpecificationBase, ContextHolder { public: explicit Specification() : should(*this), contextPtr(NULL) { } virtual ~Specification() { static_cast(this)->destroyContext(); } /** * Create the context object. Can be overridden in derived specification class. */ Context* createContext() { return new Context; } /** * Destroy the context object. Can be overridden in derived specification class. */ void destroyContext() { delete contextPtr; contextPtr = NULL; } public: // Expectations, these are used through specify-macro template InvokingType invoking(F f) { InvokingType invocation(boost::bind(f, &context())); return invocation; } template InvokingType invoking(F f, Arg1 arg1) { InvokingType invocation(boost::bind(f, &context(), arg1)); return invocation; } template InvokingType invoking(F f, Arg1 arg1, Arg2 arg2) { InvokingType invocation(boost::bind(f, &context(), arg1, arg2)); return invocation; } template InvokingType invoking(F f, Arg1 arg1, Arg2 arg2, Arg3 arg3) { InvokingType invocation(boost::bind(f, &context(), arg1, arg2, arg3)); return invocation; } template InvokingType invoking(F f, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4) { InvokingType invocation(boost::bind(f, &context(), arg1, arg2, arg3, arg4)); return invocation; } template InvokingType invoking(F f, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5) { InvokingType invocation(boost::bind(f, &context(), arg1, arg2, arg3, arg4, arg5)); return invocation; } public: // from Runnable void operator()(Reporter* reporter) { reporter->specificationStarted(*this); const int count(SpecificationBase::behaviors.size()); for(int i = 0; i < count; ++i) { contextPtr = static_cast(this)->createContext(); Functor& behavior = *(SpecificationBase::behaviors[i]); SpecificationBase::executeBehavior(behavior, reporter); static_cast(this)->destroyContext(); } reporter->specificationEnded(SpecificationBase::getName()); } public: // Vocabulary Context& context() { return *contextPtr; } ShouldType should; protected: Context* contextPtr; private: Specification(const Specification&); Specification& operator=(const Specification&); }; template class Specification : public SpecificationBase { public: Specification() { } public: // from Runnable void operator()(Reporter* reporter) { reporter->specificationStarted(*this); const int count(SpecificationBase::behaviors.size()); for(int i = 0; i < count; ++i) { Functor& behavior = *(SpecificationBase::behaviors[i]); SpecificationBase::executeBehavior(behavior, reporter); } reporter->specificationEnded(SpecificationBase::getName()); } public: ShouldType should; private: Specification(const Specification&); Specification& operator=(const Specification&); }; } #endif /*SPECIFICATION_H_*/