// This file is generated automatically. Do not edit. #ifndef ENHEDRON_MOSQUITONET_H_ #define ENHEDRON_MOSQUITONET_H_ // File: Enhedron/Util.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include namespace Enhedron { namespace Impl { namespace Util { using std::enable_if; using std::is_base_of; using std::move; using std::make_unique; using std::unique_ptr; class NoCopy { public: NoCopy() = default; NoCopy(NoCopy&&) = default; NoCopy& operator=(NoCopy&&) = default; NoCopy(const NoCopy&) = delete; NoCopy& operator=(const NoCopy&) = delete; }; class NoCopyMove : public NoCopy { public: NoCopyMove() = default; NoCopyMove(NoCopyMove&&) = delete; NoCopyMove& operator=(NoCopyMove&&) = delete; }; template class Out final { public: template Out(Out value) : value(value.value) { } explicit Out(ValueType& value) : value(&value) { } ValueType& get() { return *value; } const ValueType& get() const { return *value; } ValueType& operator*() { return *value; } const ValueType& operator*() const { return *value; } ValueType* operator->() { return value; } const ValueType* operator->() const { return value; } private: template friend class Out; ValueType* value; }; template Out out(ValueType& value) { return Out(value); } template void unused(Value& ...) { } class Finally final: public NoCopy { // std::function requires the functor to be copyable (because it's copyable). struct BaseFunctor { virtual ~BaseFunctor() {} virtual void operator()() = 0; }; template class DerivedFunctor final : public BaseFunctor { Functor f; public: DerivedFunctor(Functor f) : f(move(f)) {} virtual ~DerivedFunctor() {} virtual void operator()() override { f(); } }; unique_ptr functor; bool valid = true; public: template Finally(Functor functor) : functor(make_unique>(move(functor))) {} Finally(Finally&& source) : functor(move(source.functor)), valid(source.valid) { source.valid = false; } Finally& operator=(Finally&& source) { functor = move(source.functor); valid = move(source.valid); source.valid = false; return *this; } ~Finally() { close(); } void close() { if (valid) { (*functor)(); } valid = false; } template static Finally wrap(Object object) { return Finally([object(move(object))] {}); } static Finally empty() { return Finally([] {}); } }; }}} namespace Enhedron { using Impl::Util::NoCopy; using Impl::Util::NoCopyMove; using Impl::Util::Out; using Impl::Util::out; using Impl::Util::unused; using Impl::Util::Finally; } // File: Enhedron/Util/MetaProgramming.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include namespace Enhedron { namespace Util { namespace Impl { namespace Impl_MetaProgramming { template struct TailArgPlaceHolder { static TailArgPlaceHolder instance; }; template TailArgPlaceHolder TailArgPlaceHolder::instance; }}}} namespace std { template struct is_placeholder<::Enhedron::Util::Impl::Impl_MetaProgramming::TailArgPlaceHolder> : integral_constant { }; } namespace Enhedron { namespace Util { namespace Impl { namespace Impl_MetaProgramming { using std::tuple; using std::index_sequence; using std::index_sequence_for; using std::forward; using std::get; using std::remove_reference_t; using std::remove_extent_t; using std::conditional_t; using std::is_array; using std::is_function; using std::add_pointer_t; using std::enable_if_t; template auto bindFirst(BoundFunctor&& f, Value value, index_sequence) { return bind(forward(f), value, TailArgPlaceHolder::instance...); } template auto extractParameterPack(Functor&& f, index_sequence, const tuple& args) { return f(get(args)...); } template auto extractParameterPack(Functor&& f, index_sequence, tuple&& args) { return f(get(forward>(args))...); } template auto extractParameterPack(Functor&& f, const tuple& args) { return extractParameterPack(forward(f), index_sequence_for(), args); } template auto extractParameterPack(Functor&& f, tuple&& args) { return extractParameterPack(forward(f), index_sequence_for(), forward>(args)); } template void mapParameterPack(Functor&&) { } template void mapParameterPack(Functor&& f, const Head& head, const Args&... args) { f(head); mapParameterPack(forward(f), args...); } template class DecayArrayAndFunction { public: using U = remove_reference_t; using type = conditional_t::value, remove_extent_t*, conditional_t::value, add_pointer_t, T >>; }; template using DecayArrayAndFunction_t = typename DecayArrayAndFunction::type; template class StoreArgs final: public NoCopy { using TupleType = tuple...>; TupleType args; template auto applyExtraBeforeImpl(Functor&& functor, index_sequence, ExtraArgs&&... extraArgs) { return functor(forward(extraArgs)..., forward(get(args))...); } template auto applyExtraAfterImpl(Functor&& functor, index_sequence, ExtraArgs&&... extraArgs) { return functor(forward(get(args))..., forward(extraArgs)...); } public: // RValue reference arguments will be moved into this container. Everything else will be copied. StoreArgs(Args&&... args) : args(forward(args)...) { } template auto apply(Functor&& functor) { return extractParameterPack(forward(functor), args); } template auto applyExtraBefore(Functor&& functor, ExtraArgs&&... extraArgs) { return applyExtraBeforeImpl( forward(functor), index_sequence_for(), forward(extraArgs)... ); } template auto applyExtraAfter(Functor&& functor, ExtraArgs&&... extraArgs) { return applyExtraAfterImpl( forward(functor), index_sequence_for(), forward(extraArgs)... ); } }; }}}} namespace Enhedron { namespace Util { using Impl::Impl_MetaProgramming::StoreArgs; using Impl::Impl_MetaProgramming::DecayArrayAndFunction; using Impl::Impl_MetaProgramming::DecayArrayAndFunction_t; using Impl::Impl_MetaProgramming::bindFirst; using Impl::Impl_MetaProgramming::mapParameterPack; using Impl::Impl_MetaProgramming::extractParameterPack; }} // File: Enhedron/Util/Enum.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #ifndef ENHEDRON_UTIL_ENUM_H_ #define ENHEDRON_UTIL_ENUM_H_ #include #include namespace Enhedron { namespace Util { namespace Impl { namespace Enum { using std::runtime_error; using std::underlying_type_t; /** * Convert a value to an enum safely. The enum must have "LAST_ENUM_VALUE" as the last * enumerated value, and must be a given enum starting at 0 and being densely populated. For example: * * enum class MyEnum { * VALUE_0, * VALUE_1, * LAST_ENUM_VALUE = VALUE_1 * }; */ template Enum toEnum(Value value) { if (value >= 0 && value <= static_cast>(Enum::LAST_ENUM_VALUE)) { return static_cast(value); } throw runtime_error("Value out of range for enum"); } /** * Tag a type with an enumerated value to create a distinct type. Useful to differentiate values of the same type. * For example, to stop first and last names being interchangeable in the type system: * enum class Name { * FIRST, * LAST * }; * * using FirstName = TaggedValue; * using LastName = TaggedValue; */ template class TaggedValue final { Value value; public: TaggedValue(Value value) : value(move(value)) { } Value& operator*() { return value; } const Value& operator*() const { return value; } Value* operator->() { return &value; } const Value* operator->() const { return &value; } }; }}}} namespace Enhedron { namespace Util { using Impl::Enum::toEnum; using Impl::Enum::TaggedValue; }} #endif /* ENHEDRON_UTIL_ENUM_H_ */ // File: Enhedron/Util/Optional.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include namespace Enhedron { namespace Util { namespace Impl { namespace Impl_Optional { using std::unique_ptr; using std::make_unique; using std::forward; class None final {}; static constexpr const None none{}; template class optional final { unique_ptr value_; template friend class optional; public: optional() = default; optional(const optional& other) { if (bool(other)) { value_ = make_unique(*other.value_); } else { value_.reset(); } } optional& operator=(const optional& other) { if (bool(other)) { value_ = make_unique(*other.value_); } else { value_.reset(); } return *this; } optional(const Value& value) : value_(make_unique(value)) {} optional(Value&& value) : value_(make_unique(forward(value))) {} optional(None) {} Value& get() const { return *value_; } Value& operator*() const { return *value_; } Value* operator->() const { return value_.get(); } void reset() { value_.reset(); } operator bool() const { return bool(value_); } }; template class optional final { Value* value_ = nullptr; public: optional() = default; optional(Value& value) : value_(&value) {} optional(None) {} Value& get() const { return *value_; } Value& operator*() const { return *value_; } Value* operator->() const { return value_; } void reset() { value_ = nullptr; } operator bool() const { return value_ != nullptr; } }; }}}} namespace Enhedron { namespace Util { using Impl::Impl_Optional::none; using Impl::Impl_Optional::optional; }} // File: Enhedron/Assertion/Configurable.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Enhedron { namespace Assertion { template class HasOutputOperator { template () << std::declval())> static std::integral_constant test(); template static std::integral_constant test(Args...); public: static constexpr bool value = decltype(test())::value; }; template class IsStlContainer { using True = std::integral_constant; template struct test : std::false_type {}; template struct test> : True{}; // MSVC doesn't like the parameter packs for these. Suspect it just doesn't like the // parameter packs for any container and is just using the defaults for allocators. template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; template struct test> : True{}; public: static constexpr bool value = test>::value; }; template struct Convert { template::value>* = nullptr> static std::string toString(const Value &value) { std::ostringstream valueString; valueString << value; return valueString.str(); } template::value>* = nullptr> static std::string toString(const Value &value) { return ""; } }; template<> struct Convert { static inline std::string toString(const std::nullptr_t &) { return "nullptr"; } }; template<> struct Convert { static inline std::string toString(bool value) { return value ? "true" : "false"; } }; template<> struct Convert { static inline std::string toString(const std::string& s) { return "\"" + s + "\""; } }; template struct Convert, char*>::value>> { static inline std::string toString(const char* s) { return "\"" + std::string(s) + "\""; } }; template struct Convert>::value>> { static std::string toString(Value value) { std::ostringstream valueString; valueString << static_cast>>(value); return valueString.str(); } }; template struct Convert>::value>> { static std::string toString(Value value) { return ""; } }; template struct Convert::value>> { static inline std::string toString(const Container& value) { std::string result("["); bool isFirst = true; for (const auto& element : value) { if ( ! isFirst) { result += ", "; } isFirst = false; result += Convert::toString(element); } result += "]"; return result; } }; }} namespace Enhedron { namespace Assertion { namespace Impl { namespace Configurable { using Util::StoreArgs; using Util::mapParameterPack; using Util::extractParameterPack; using Util::DecayArrayAndFunction_t; using Util::optional; using Util::none; using std::enable_if_t; using std::is_base_of; using std::is_same; using std::ostringstream; using std::string; using std::move; using std::forward; using std::vector; using std::result_of_t; using std::exception; using std::function; using std::pair; using std::tuple; using std::tie; using std::add_lvalue_reference_t; using std::index_sequence; using std::index_sequence_for; using std::get; using std::reference_wrapper; using std::remove_reference_t; using std::conditional_t; using std::ref; using std::cref; using std::is_function; class Expression { }; template using IsExpression = enable_if_t::value>*; template using IsNotExpression = enable_if_t::value> *; template using EitherIsExpression = enable_if_t< is_base_of::value || is_base_of::value> *; class Variable final { public: Variable(string name, string value, string file, int line) : name_(move(name)), value_(move(value)), file_(move(file)), line_(move(line)) { } const string &name() const { return name_; } const string &value() const { return value_; } const string &file() const { return file_; } int line() const { return line_; } private: string name_; string value_; string file_; int line_; }; template class Literal final : public Expression { public: using ResultType = DecayArrayAndFunction_t; explicit Literal(const Value &value) : value(value) { } string makeName() const { return Convert::toString(value); } void appendVariables(vector &) const { } const Value& evaluate() { return value; } private: const Value &value; }; template class UnaryOperator final : public Expression { public: using ResultType = DecayArrayAndFunction_t>; explicit UnaryOperator(const char *operatorName, Functor functor, Arg arg) : operatorName(operatorName), functor(move(functor)), arg(move(arg)) { } string makeName() const { ostringstream valueString; valueString << "( " << operatorName << " " << arg.makeName() << ")"; return valueString.str(); } void appendVariables(vector &variableList) const { arg.appendVariables(variableList); } ResultType evaluate() { return functor(arg.evaluate()); } private: const char *operatorName; Functor functor; Arg arg; }; template class BinaryOperator final : public Expression { public: using ResultType = DecayArrayAndFunction_t>; explicit BinaryOperator(const char *operatorName, Functor functor, Lhs lhs, Rhs rhs) : operatorName(operatorName), functor(move(functor)), lhs(move(lhs)), rhs(move(rhs)) { } string makeName() const { ostringstream valueString; valueString << "(" << lhs.makeName() << " " << operatorName << " " << rhs.makeName() << ")"; return valueString.str(); } void appendVariables(vector &variableList) const { lhs.appendVariables(variableList); rhs.appendVariables(variableList); } ResultType evaluate() { return functor(lhs.evaluate(), rhs.evaluate()); } private: const char *operatorName; Functor functor; Lhs lhs; Rhs rhs; }; template struct DecayExpression { using type = T; }; template struct DecayExpression>::value>> { using type = typename T::ResultType; }; template using DecayExpression_t = typename DecayExpression::type; template class FunctionValue final : public Expression { public: using ResultType = DecayArrayAndFunction_t...)>>; explicit FunctionValue(string name, Functor&& functor, const char *file, int line, Args&&... args) : name(move(name)), functor(move(functor)), fileAndLine(FileLine{file, line}), args(forward(args)...) {} explicit FunctionValue(string name, Functor&& functor, Args&&... args) : name(move(name)), functor(move(functor)), args(forward(args)...) {} string makeName() const { ostringstream valueString; valueString << name << "("; extractParameterPack( [this, &valueString] (const Args&... unpackedArgs) { makeParameterNames(out(valueString), unpackedArgs...); }, args ); valueString << ")"; if (exceptionMessage) { valueString << " threw \"" << *exceptionMessage << "\""; } return valueString.str(); } void appendVariables(vector& variableList) const { if (fileAndLine) { variableList.emplace_back(name, "function", fileAndLine->file, fileAndLine->line); } extractParameterPack( [this, &variableList] (const Args&... unpackedArgs) { appendParameterVariableList(variableList, unpackedArgs...); }, args ); } ResultType evaluate() { return extractParameterPack( [this] (Args&&... extractedArgs) { return functor(getParameterValue(forward(extractedArgs))...); }, move(args) ); } void setException(const exception& e) { exceptionMessage = optional(e.what()); } private: template void makeParameterNames(Out parameters, const Arg1& arg1, const Arg2& arg2, const Tail&... tail) const { (*parameters) << getParameterName(arg1) << ", "; makeParameterNames(parameters, arg2, tail...); } template void makeParameterNames(Out parameters, const Arg& arg) const { (*parameters) << getParameterName(arg); } void makeParameterNames(Out parameters) const {} template = nullptr> string getParameterName(const Arg& arg) const { return arg.makeName(); } template = nullptr> string getParameterName(const Arg& arg) const { return Convert::toString(arg); } template = nullptr> auto getParameterValue(Arg&& arg) { return arg.evaluate(); } template = nullptr> auto getParameterValue(Arg&& arg) { return arg; } template void appendParameterVariableList( vector& variableList, const HeadArg& arg, const TailArgs&... tailArgs ) const { appendParameterVariable(variableList, arg); appendParameterVariableList(variableList, tailArgs...); } void appendParameterVariableList(vector& variableList) const {} template = nullptr> void appendParameterVariable(vector& variableList, const Arg& arg) const { return arg.appendVariables(variableList); } template = nullptr> void appendParameterVariable(vector&, const Arg&) const { } string name; Functor functor; struct FileLine { const char* file; int line; }; optional fileAndLine; optional exceptionMessage; tuple args; }; template class Function final { string name_; Functor functor_; public: Function(string name, Functor&& functor) : name_(move(name)), functor_(functor) {} template auto operator()(Args&&... args) { return FunctionValue(name_, Functor(functor_), forward(args)...); } }; template auto makeFunction(string name, Functor&& functor) { return Function(move(name), forward(functor)); } template class VariableRefExpression final : public Expression { public: using ResultType = DecayArrayAndFunction_t; explicit VariableRefExpression(const char *variableName, Value& value, const char *file, int line) : variableName(variableName), value(value), file(file), line(line) { } string makeName() const { return variableName; } void appendVariables(vector &variableList) const { variableList.emplace_back(variableName, Convert::toString(value), file, line); } ResultType evaluate() { return value; } template auto operator()(Args&&... args) { return FunctionValue, Args...>( variableName, cref(value), file, line, forward(args)... ); } private: const char *variableName; Value& value; const char *file; int line; }; template class VariableValueExpression final : public Expression { public: using ResultType = DecayArrayAndFunction_t; explicit VariableValueExpression(const char *variableName, Value&& value, const char *file, int line) : variableName(variableName), value(move(value)), file(file), line(line) { } string makeName() const { return variableName; } void appendVariables(vector &variableList) const { variableList.emplace_back(variableName, Convert::toString(value), file, line); } ResultType evaluate() { return value; } // Only call this once! It will move the underlying value. template FunctionValue operator()(Args&&... args) { return FunctionValue(variableName, move(value), file, line, forward(args)...); } private: const char *variableName; Value value; const char *file; int line; }; template auto makeVariable(const char *name, Value& value, const char *file, int line) { return VariableRefExpression(name, value, file, line); } template::value>* = nullptr> auto makeVariable(const char *name, Value&& value, const char *file, int line) { return VariableValueExpression>(name, ref(value), file, line); } template::value>* = nullptr> auto makeVariable(const char *name, Value&& value, const char *file, int line) { return VariableValueExpression(name, move(value), file, line); } template, IsExpression> * = nullptr> auto apply(const char *operationName, Operation operation, const Lhs &lhs, const Rhs &rhs) { return BinaryOperator(operationName, move(operation), lhs, rhs); } template, IsNotExpression> * = nullptr> auto apply(const char *operationName, Operation operation, const Lhs &lhs, const Rhs &rhs) { return apply(operationName, move(operation), lhs, Literal(rhs)); } template, IsExpression> * = nullptr> auto apply(const char *operationName, Operation operation, const Lhs &lhs, const Rhs &rhs) { return apply(operationName, move(operation), Literal(lhs), rhs); } template = nullptr> auto apply(const char *operationName, Operation operation, const Arg &arg) { return UnaryOperator(operationName, move(operation), arg); } // Unary operators template = nullptr> auto operator!(const Arg &arg) { return apply("!", [](const auto& arg) { return !arg; }, arg); } template = nullptr> auto operator~(const Arg &arg) { return apply("~", [](const auto& arg) { return ~arg; }, arg); } template = nullptr> auto operator+(const Arg &arg) { return apply("+", [](const auto& arg) { return +arg; }, arg); } template = nullptr> auto operator-(const Arg &arg) { return apply("-", [](const auto& arg) { return -arg; }, arg); } // Binary operators template = nullptr> auto operator==(const Lhs &lhs, const Rhs &rhs) { return apply("==", [](const auto&lhs, const auto& rhs) { return lhs == rhs; }, lhs, rhs); } template = nullptr> auto operator!=(const Lhs &lhs, const Rhs &rhs) { return apply("!=", [](const auto&lhs, const auto& rhs) { return lhs != rhs; }, lhs, rhs); } template = nullptr> auto operator>(const Lhs &lhs, const Rhs &rhs) { return apply(">", [](const auto&lhs, const auto& rhs) { return lhs > rhs; }, lhs, rhs); } template = nullptr> auto operator>=(const Lhs &lhs, const Rhs &rhs) { return apply(">=", [](const auto&lhs, const auto& rhs) { return lhs >= rhs; }, lhs, rhs); } template = nullptr> auto operator<(const Lhs &lhs, const Rhs &rhs) { return apply("<", [](const auto&lhs, const auto& rhs) { return lhs < rhs; }, lhs, rhs); } template = nullptr> auto operator<=(const Lhs &lhs, const Rhs &rhs) { return apply("<=", [](const auto&lhs, const auto& rhs) { return lhs <= rhs; }, lhs, rhs); } template = nullptr> auto operator&&(const Lhs &lhs, const Rhs &rhs) { return apply("&&", [](const auto&lhs, const auto& rhs) { return lhs && rhs; }, lhs, rhs); } template = nullptr> auto operator||(const Lhs &lhs, const Rhs &rhs) { return apply("||", [](const auto&lhs, const auto& rhs) { return lhs || rhs; }, lhs, rhs); } template = nullptr> auto operator+(const Lhs &lhs, const Rhs &rhs) { return apply("+", [](const auto&lhs, const auto& rhs) { return lhs + rhs; }, lhs, rhs); } template = nullptr> auto operator-(const Lhs &lhs, const Rhs &rhs) { return apply("-", [](const auto&lhs, const auto& rhs) { return lhs - rhs; }, lhs, rhs); } template = nullptr> auto operator*(const Lhs &lhs, const Rhs &rhs) { return apply("*", [](const auto&lhs, const auto& rhs) { return lhs * rhs; }, lhs, rhs); } template = nullptr> auto operator/(const Lhs &lhs, const Rhs &rhs) { return apply("/", [](const auto&lhs, const auto& rhs) { return lhs / rhs; }, lhs, rhs); } template = nullptr> auto operator%(const Lhs &lhs, const Rhs &rhs) { return apply("%", [](const auto&lhs, const auto& rhs) { return lhs % rhs; }, lhs, rhs); } template = nullptr> auto operator&(const Lhs &lhs, const Rhs &rhs) { return apply("&", [](const auto&lhs, const auto& rhs) { return lhs & rhs; }, lhs, rhs); } template = nullptr> auto operator|(const Lhs &lhs, const Rhs &rhs) { return apply("|", [](const auto&lhs, const auto& rhs) { return lhs | rhs; }, lhs, rhs); } template = nullptr> auto operator^(const Lhs &lhs, const Rhs &rhs) { return apply("^", [](const auto&lhs, const auto& rhs) { return lhs ^ rhs; }, lhs, rhs); } template = nullptr> auto operator<<(const Lhs &lhs, const Rhs &rhs) { return apply("<<", [](const auto&lhs, const auto& rhs) { return lhs << rhs; }, lhs, rhs); } template = nullptr> auto operator>>(const Lhs &lhs, const Rhs &rhs) { return apply(">>", [](const auto&lhs, const auto& rhs) { return lhs >> rhs; }, lhs, rhs); } struct FailureHandler { virtual ~FailureHandler() {}; virtual bool notifyPassing() const = 0; virtual void pass(optional description, const string &expressionText, const vector &variableList) = 0; virtual void fail(optional description, const string &expressionText, const vector &variableList) = 0; }; template vector buildVariableList( const Expression& expression, const ContextVariableList&... contextVariableList ) { vector variableList; expression.appendVariables(variableList); vector contextVariableVector(contextVariableList...); variableList.insert(variableList.end(), contextVariableVector.begin(), contextVariableVector.end()); return variableList; } template void processFailure( Out failureHandler, optional description, Expression expression, ContextVariableList... contextVariableList ) { failureHandler->fail(move(description), expression.makeName(), buildVariableList(expression, contextVariableList...)); } template void processSuccess( Out failureHandler, optional description, Expression expression, ContextVariableList... contextVariableList ) { if (failureHandler->notifyPassing()) { failureHandler->pass(move(description), expression.makeName(), buildVariableList(expression, contextVariableList...)); } } template bool CheckWithFailureHandlerImpl( Out failureHandler, optional description, Expression expression, Tail... tail ) { if ( ! static_cast(expression.evaluate())) { processFailure(failureHandler, move(description), move(expression), move(tail)...); return false; } processSuccess(failureHandler, move(description), move(expression), move(tail)...); return true; } template = nullptr> bool CheckWithFailureHandler( Out failureHandler, Expression expression, Tail... tail ) { return CheckWithFailureHandlerImpl(failureHandler, none, move(expression), move(tail)...); } template = nullptr> bool CheckWithFailureHandler( Out failureHandler, string description, Tail... tail ) { return CheckWithFailureHandlerImpl(failureHandler, move(description), move(tail)...); } template< typename Exception, typename Expression, typename... ContextVariableList, enable_if_t::value> * = nullptr > bool CheckThrowsWithFailureHandlerImpl( Out failureHandler, optional description, Expression expression, ContextVariableList... contextVariableList ) { try { expression.evaluate(); processFailure(failureHandler, move(description), move(expression), move(contextVariableList)...); return false; } catch (const exception&) { processSuccess(failureHandler, move(description), move(expression), move(contextVariableList)...); } return true; } template< typename Exception, typename Functor, typename... Args, typename... ContextVariableList, enable_if_t::value> * = nullptr > bool CheckThrowsWithFailureHandlerImpl( Out failureHandler, optional description, FunctionValue expression, ContextVariableList... contextVariableList ) { try { expression.evaluate(); processFailure(failureHandler, move(description), move(expression), move(contextVariableList)...); return false; } catch (const Exception&) { processSuccess(failureHandler, move(description), move(expression), move(contextVariableList)...); } catch (const exception &e) { expression.setException(e); processFailure(failureHandler, move(description), move(expression), move(contextVariableList)...); return false; } return true; } template< typename Exception, typename Expression, typename... Tail, IsExpression = nullptr > bool CheckThrowsWithFailureHandler( Out failureHandler, Expression expression, Tail... tail ) { return CheckThrowsWithFailureHandlerImpl(failureHandler, none, move(expression), move(tail)...); } template< typename Exception, typename... Tail > bool CheckThrowsWithFailureHandler( Out failureHandler, string description, Tail... tail ) { return CheckThrowsWithFailureHandlerImpl(failureHandler, move(description), move(tail)...); } }}}} namespace Enhedron { namespace Assertion { using Impl::Configurable::CheckWithFailureHandler; using Impl::Configurable::CheckThrowsWithFailureHandler; using Impl::Configurable::IsExpression; using Impl::Configurable::Expression; using Impl::Configurable::Variable; using Impl::Configurable::makeFunction; using Impl::Configurable::processFailure; using Impl::Configurable::FailureHandler; using Impl::Configurable::Function; }} #define M_ENHEDRON_VAL(expression) \ (::Enhedron::Assertion::Impl::Configurable::makeVariable((#expression), (expression), (__FILE__), (__LINE__))) // File: Enhedron/Assertion.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include namespace Enhedron { namespace Impl { namespace Impl_Assertion { using ::Enhedron::Util::optional; using std::forward; using std::terminate; using std::vector; using std::string; using std::cerr; using namespace ::Enhedron::Assertion; struct CerrFailureHandler final: FailureHandler { virtual ~CerrFailureHandler() override {} virtual bool notifyPassing() const override { return false; } virtual void pass(optional description, const string &expressionText, const vector &variableList) override { } virtual void fail(optional description, const string &expressionText, const vector &variableList) override { cerr << "Assert failed: " << expressionText << "\n"; for (const auto &variable : variableList) { cerr << " " << variable.name() << " = " << variable.value() << ": in file " << variable.file() << ", line " << variable.line() << "\n"; } cerr.flush(); #ifndef NDEBUG terminate(); #endif } }; static CerrFailureHandler failureHandler; template void Assert(Args&&... args) { CheckWithFailureHandler(out(failureHandler), forward(args)...); } template void AssertThrows(Args&&... args) { CheckThrowsWithFailureHandler(out(failureHandler), forward(args)...); } }}} namespace Enhedron { using Impl::Impl_Assertion::Assert; } #define VAR M_ENHEDRON_VAL // File: Enhedron/Test/Results.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include namespace Enhedron { namespace Test { namespace Impl { namespace Impl_Results { using std::exception; using std::string; using std::unique_ptr; using std::make_unique; using std::ostream; using std::endl; using std::vector; using Assertion::FailureHandler; using Assertion::Variable; using Util::optional; class Stats { uint64_t fixtures_ = 0; uint64_t tests_ = 0; uint64_t checks_ = 0; uint64_t failedTests_ = 0; uint64_t failedChecks_ = 0; public: Stats& operator+=(Stats rhs) { fixtures_ += rhs.fixtures_; tests_ += rhs.tests_; checks_ += rhs.checks_; failedTests_ += rhs.failedTests_; failedChecks_ += rhs.failedChecks_; return *this; } void addFixture() { ++fixtures_; } void addTest() { ++tests_; } void addCheck() { ++checks_; } void failTest() { ++failedTests_; } void failCheck() { ++failedChecks_; } uint64_t fixtures() const { return fixtures_; } uint64_t tests() const { return tests_; } uint64_t checks() const { return checks_; } uint64_t failedTests() const { return failedTests_; } uint64_t failedChecks() const { return failedChecks_; } }; class ResultTest: public NoCopy, public FailureHandler { public: virtual ~ResultTest() {} virtual unique_ptr section(string description) = 0; virtual void failByException(const exception& e) = 0; }; class ResultContext: public NoCopy { public: virtual ~ResultContext() {} virtual unique_ptr child(const string& name) = 0; virtual void listTest(const string& name) = 0; virtual unique_ptr test(const string& name) = 0; }; class Results: public ResultContext { public: virtual ~Results() {} virtual void finish(const Stats& stats) = 0; }; enum class Verbosity { SILENT, SUMMARY, CONTEXTS, FIXTURES, SECTIONS, EXHAUSTIVE_SECTIONS, CHECKS, CHECKS_EXPRESSION, VARIABLES }; class HumanResultTest final: public ResultTest { Out outputStream_; size_t depth_; Verbosity verbosity_; void indent(size_t relativeDepth) { for (size_t totalDepth = 1 + depth_ + relativeDepth; totalDepth > 0; --totalDepth) { (*outputStream_) << " "; } } void printVariables(const vector &variableList) { for (const auto& variable : variableList) { indent(2); (*outputStream_) << variable.name() << " = " << variable.value() << ": file \"" << variable.file() << "\", line " << variable.line() << ".\n"; } } public: HumanResultTest(Out outputStream, size_t depth, Verbosity verbosity) : outputStream_(outputStream), depth_(depth), verbosity_(verbosity) {} virtual unique_ptr section(string description) override { if (verbosity_ >= Verbosity::SECTIONS) { indent(1); (*outputStream_) << "when: " << description << "\n"; } return make_unique(outputStream_, depth_ + 1, verbosity_); } virtual bool notifyPassing() const override { return verbosity_ >= Verbosity::CHECKS; } virtual void fail(optional description, const string &expressionText, const vector &variableList) override { // TODO: Print out test details indent(1); (*outputStream_) << "CHECK FAILED: " << expressionText << "\n"; printVariables(variableList); } virtual void pass(optional description, const string &expressionText, const vector &variableList) override { indent(1); (*outputStream_) << "then"; if (description) { (*outputStream_) << ": " << *description; } if (verbosity_ >= Verbosity::CHECKS_EXPRESSION) { (*outputStream_) << ": " << expressionText; } (*outputStream_) << "\n"; if (verbosity_ >= Verbosity::VARIABLES) { printVariables(variableList); } } virtual void failByException(const exception& e) override { indent(0); (*outputStream_) << "TEST FAILED WITH EXCEPTION: " << e.what() << endl; } }; template class HumanResultContext: public Base { Out outputStream_; bool contextPrinted_ = false; string path_; Verbosity verbosity_; void writeTestName(const string& testName) { if (verbosity_ >= Verbosity::CONTEXTS) { if (!contextPrinted_) { contextPrinted_ = true; *outputStream_ << path_ << "\n"; } } if (verbosity_ >= Verbosity::FIXTURES) { *outputStream_ << " Given: " << testName << endl; } } public: HumanResultContext(Out outputStream, const string& name, Verbosity verbosity) : outputStream_(outputStream), path_(name), verbosity_(verbosity) { } virtual unique_ptr child(const string& name) override { string childPath(path_); if ( ! path_.empty()) { childPath += "/"; } childPath += name; return make_unique>(outputStream_, childPath, verbosity_); } virtual void listTest(const string& name) override { writeTestName(name); } virtual unique_ptr test(const string& name) override { writeTestName(name); return make_unique(outputStream_, 0, verbosity_); } }; class HumanResults final: public HumanResultContext { Out outputStream_; Verbosity verbosity_; public: HumanResults(Out outputStream, Verbosity verbosity) : HumanResultContext(outputStream, "", verbosity), outputStream_(outputStream), verbosity_(verbosity) {} virtual void finish(const Stats& stats) override { if (verbosity_ >= Verbosity::SUMMARY) { if (stats.failedTests() > 0) { *outputStream_ << "FAILED TESTS: " << stats.failedTests() << "\n"; } if (stats.failedChecks() > 0) { *outputStream_ << "FAILED CHECKS: " << stats.failedChecks() << "\n"; } *outputStream_ << "Totals: " << stats.tests() << " tests, " << stats.checks() << " checks, " << stats.fixtures() << " fixtures\n"; } } }; }}}} namespace Enhedron { namespace Test { using Impl::Impl_Results::Results; using Impl::Impl_Results::ResultContext; using Impl::Impl_Results::ResultTest; using Impl::Impl_Results::HumanResults; using Impl::Impl_Results::Stats; using Impl::Impl_Results::Verbosity; }} // File: Enhedron/Test/Suite.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #include #include #include #include namespace Enhedron { namespace Test { namespace Impl { namespace Impl_Suite { using namespace Assertion; using Util::TaggedValue; using Util::StoreArgs; using Util::DecayArrayAndFunction_t; using Util::bindFirst; using Util::optional; using Util::none; using std::forward; using std::vector; using std::move; using std::exception; using std::function; using std::string; using std::unique_ptr; using std::shared_ptr; using std::make_unique; using std::tuple; using std::index_sequence; using std::index_sequence_for; using std::get; using std::remove_reference; using std::bind; using std::ref; using std::runtime_error; using std::cout; using std::regex; using std::regex_match; using std::reference_wrapper; using PathList = vector>>; class Context: public NoCopy { public: virtual ~Context() {} virtual void list(const PathList& pathList, Out results, size_t depth) const = 0; virtual Stats run(const PathList& pathList, Out results, size_t depth) = 0; }; using ContextList = vector>; class Register final: public NoCopyMove { public: static void add(unique_ptr context) { instance().contextList.emplace_back(move(context)); } static void list(const PathList& pathList, Out results) { for (const auto& context : instance().contextList) { context->list(pathList, results, 0); } } static Stats run(const PathList& pathList, Out results) { Stats stats; for (const auto& context : instance().contextList) { stats += context->run(pathList, results, 0); } results->finish(stats); return stats; } private: Register() = default; static Register& instance() { static Register theInstance; return theInstance; } ContextList contextList; }; class NodeContext final: public Context { public: NodeContext(const string& name, vector> contextList) : name(name), contextList(move(contextList)) {} virtual void list(const PathList& pathList, Out results, size_t depth) const override { auto nextPathList = getMatchingPaths(pathList, depth); auto resultChild = results->child(name); if (nextPathList) { for (const auto& context : contextList) { context->list(*nextPathList, out(*resultChild), depth + 1); } } } virtual Stats run(const PathList& pathList, Out results, size_t depth) override { Stats stats; auto nextPathList = getMatchingPaths(pathList, depth); if (nextPathList) { auto resultChild = results->child(name); for (const auto& context : contextList) { stats += context->run(*nextPathList, out(*resultChild), depth + 1); } } return stats; } private: optional getMatchingPaths(const PathList& pathList, size_t depth) const { if (pathList.empty()) { return pathList; } vector>> nextPathList; for (const auto& path : pathList) { if (path->size() > depth) { if (regex_match(name, (*path)[depth])) { nextPathList.push_back(path); } } else { return pathList; } } if (nextPathList.empty()) { return none; } return move(nextPathList); } string name; vector> contextList; }; template void makeContextList(Out contextList, unique_ptr childContext, ContextListType&&... childContextList) { contextList->emplace_back(move(childContext)); makeContextList(contextList, forward(childContextList)...); } inline void makeContextList(Out) { } template unique_ptr context(const string& name, ContextListType&&... childContextList) { ContextList contextList; makeContextList(out(contextList), forward(childContextList)...); return make_unique(name, move(contextList)); } class Suite: public NoCopy { public: template Suite(const string& name, ContextListType&&... childContextList) { Register::add(context(name, forward(childContextList)...)); } }; class WhenRunner { struct StackElement { size_t index = 0; size_t current = 0; }; vector whenStack; vector> whenCurrentStack; size_t whenDepth_ = 0; Out results_; Stats stats_; bool topWhenDone() const { const auto& top = whenStack.back(); return top.current == top.index + 1; } public: WhenRunner(Out results) : results_(results) {} template void run(Functor&& functor, Args&&... args); template void when(string description, Functor&& functor) { if (whenStack.size() <= whenDepth_) { whenStack.push_back(StackElement{}); } Finally stack([&] { ++whenStack[whenDepth_].current; }); if (whenStack[whenDepth_].index == whenStack[whenDepth_].current) { ++whenDepth_; whenCurrentStack.push_back(topResult()->section(move(description))); Finally depth([&] { --whenDepth_; whenCurrentStack.pop_back(); }); stats_.addTest(); functor(); } } Out topResult() { if (whenCurrentStack.empty()) { return results_; } return out(*whenCurrentStack.back()); } Stats stats() const { return stats_; } }; class Check : public NoCopy { Out whenRunner_; Stats stats_; friend inline Stats checkStats(const Check& check) { return check.stats_; } bool addCheck(bool ok) { stats_.addCheck(); if ( ! ok) { stats_.failCheck(); } return ok; } public: Check(Out whenRunner) : whenRunner_(whenRunner) {} template void when(string description, Functor&& functor) { whenRunner_->when(move(description), forward(functor)); } template bool operator()(Args&&... args) { return addCheck(CheckWithFailureHandler( whenRunner_->topResult(), forward(args)... )); } template bool throws(Args&&... args) { return addCheck(CheckThrowsWithFailureHandler( whenRunner_->topResult(), forward(args)... )); } template void fail(Expression expression, ContextVariableList... contextVariableList) { processFailure(whenRunner_->topResult(), none, move(expression), move(contextVariableList)...); stats_.failCheck(); } }; template void WhenRunner::run(Functor&& functor, Args&&... args) { whenStack.clear(); whenDepth_ = 0; stats_.addFixture(); do { for (auto& element : whenStack) { element.current = 0; } Check check(out(*this)); try { functor(check, forward(args)...); } catch (const exception& e) { results_->failByException(e); stats_.failTest(); } stats_ += checkStats(check); while ( ! whenStack.empty() && topWhenDone()) { whenStack.pop_back(); } if ( ! whenStack.empty()) { ++whenStack.back().index; } } while ( ! whenStack.empty()); if (stats_.tests() == 0) { stats_.addTest(); } } template class Runner final: public Context { bool included(const PathList& pathList, size_t depth) const { if (pathList.empty()) { return true; } for (const auto& path : pathList) { if (path->size() > depth) { if (regex_match(name, (*path)[depth])) { return true; } } else { return true; } } return false; } string name; Functor runTest; StoreArgs args; public: Runner(string name, Functor runTest, Args&&... args) : name(move(name)), runTest(move(runTest)), args(forward(args)...) {} virtual void list(const PathList& pathList, Out results, size_t depth) const override { if ( ! included(pathList, depth)) return; results->listTest(name); } // Must only be called once as it forwards the constructor arguments to the class. virtual Stats run(const PathList& pathList, Out results, size_t depth) override { if ( ! included(pathList, depth)) return Stats{}; return args.applyExtraBefore(runTest, name, results); } }; template class RunTest final: public NoCopy { Functor runTest; public: RunTest(Functor runTest) : runTest(move(runTest)) {} // Visual C++ 2015 seems to generate a dodgy move constructor here. RunTest(RunTest&& other) : runTest(move(other.runTest)) {} RunTest operator=(RunTest&& other) { runTest = move(other.runTest); } Stats operator()(const string& name, Out results, Args&&... args) { auto test = results->test(name); WhenRunner whenRunner(out(*test)); whenRunner.run(runTest, forward(args)...); return whenRunner.stats(); } }; // Workaround for MSVC bug. We should be able to use std forward, but it doesn't work for decayed arrays. template struct Forward { static constexpr T&& run( typename std::remove_reference::type& t ) { return std::forward(t); } static constexpr T&& run( typename std::remove_reference::type&& t ) { return std::forward(t); } }; template struct Forward { static T* run(T* t ) { return t; } }; template unique_ptr given(string name, Functor runTest, Args&&... args) { return make_unique...>, DecayArrayAndFunction_t...>>( move(name), RunTest...>(runTest), Forward>::run(args)... ); } template class RunExhaustive final: public NoCopy { Functor runTest; StoreArgs args; template static Stats exhaustive(BoundFunctor&& functor, const string& name, Out test) { WhenRunner whenRunner(out(*test)); whenRunner.run(forward(functor)); return whenRunner.stats(); } template static Stats exhaustive( BoundFunctor&& functor, const string& name, Out test, const Container& container, const BoundArgs&... tail ) { Stats stats; for (const auto& value : container) { stats += exhaustive( [&] (Check& check, auto&&... args) { functor(ref(check), value, args...); }, name, test, tail... ); } return stats; } public: RunExhaustive(Functor runTest, StoreArgs args) : runTest(move(runTest)), args(move(args)) {} Stats operator()(const string& name, Out results) { auto test = results->test(name); return args.apply([&] (const Args&... extractedArgs) { return exhaustive(move(runTest), name, out(*test), extractedArgs...); }); } }; template vector choice(Value value, Args&&... tail) { return vector{value, forward(tail)...}; } template vector constant(Value value) { return vector(1, value); } template class Exhaustive final: public NoCopy { StoreArgs args; public: Exhaustive(Args&&... args) : args(forward(args)...) {} template unique_ptr given(string name, Functor runTest) { return make_unique>>( move(name), RunExhaustive(move(runTest), move(args)) ); } }; template Exhaustive exhaustive(Args&&... args) { return Exhaustive...>(forward>(args)...); } inline void list(const PathList& pathList, Out results) { Register::list(pathList, results); } inline bool run(const PathList& pathList, Out results) { auto stats = Register::run(pathList, results); return stats.failedTests() == 0 && stats.failedChecks() == 0; } inline void list(const PathList& pathList, Verbosity verbosity) { HumanResults results(out(cout), verbosity); list(pathList, out(results)); } inline bool run(const PathList& pathList, Verbosity verbosity) { HumanResults results(out(cout), verbosity); return run(pathList, out(results)); } }}}} namespace Enhedron { namespace Test { using namespace Assertion; using Impl::Impl_Suite::Suite; using Impl::Impl_Suite::context; using Impl::Impl_Suite::Check; using Impl::Impl_Suite::given; using Impl::Impl_Suite::Exhaustive; using Impl::Impl_Suite::exhaustive; using Impl::Impl_Suite::choice; using Impl::Impl_Suite::constant; using Impl::Impl_Suite::list; using Impl::Impl_Suite::run; }} // File: Enhedron/Util/Math.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include namespace Enhedron { namespace Util { namespace Impl { namespace Math { using std::numeric_limits; // Assumes numerator + denominator + 1 doesn't overflow. template constexpr NumeratorType divideRoundingUp(NumeratorType numerator, DenominatorType denominator) { // Doesn't work for -ve numbers. static_assert(!numeric_limits::is_signed, "NumeratorType must be unsigned"); static_assert(!numeric_limits::is_signed, "DenominatorType must be unsigned"); return (numerator + denominator - NumeratorType(1u)) / denominator; } template constexpr Value makeDivisibleByRoundingDown(Value value, Modulus modulus) { // Doesn't work for -ve numbers. static_assert(!numeric_limits::is_signed, "Value must be unsigned"); static_assert(!numeric_limits::is_signed, "Modulus must be unsigned"); return (value / modulus) * modulus; } template constexpr Value makeDivisibleByRoundingUp(Value value, Modulus modulus) { // Doesn't work for -ve numbers. static_assert(!numeric_limits::is_signed, "Value must be unsigned"); static_assert(!numeric_limits::is_signed, "Modulus must be unsigned"); return ((value + modulus - 1) / modulus) * modulus; } //! Is numerator divisible by denominator template constexpr bool isDivisible(NumeratorType numerator, DenominatorType denominator) { return (numerator / denominator) * denominator == numerator; } }}}} namespace Enhedron { namespace Util { using Impl::Math::divideRoundingUp; using Impl::Math::makeDivisibleByRoundingDown; using Impl::Math::makeDivisibleByRoundingUp; using Impl::Math::isDivisible; }} // File: Enhedron/CommandLine/Parameters.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #include #include #include #include #include #include #include namespace Enhedron { namespace CommandLine { namespace Impl { namespace Impl_Parameters { using Util::bindFirst; using Util::optional; using Util::mapParameterPack; using Util::makeDivisibleByRoundingUp; using std::string; using std::ostream; using std::vector; using std::set; using std::map; using std::string; using std::move; using std::back_inserter; using std::logic_error; using std::index_sequence_for; using std::forward; using std::cout; using std::cerr; using std::runtime_error; using std::exception; using std::ostringstream; using std::min; using std::max; using std::fill_n; using std::ostream_iterator; using std::copy; enum class ExitStatus { OK, USAGE = 64, // command line usage error DATAERR = 65, // data format error NOINPUT = 66, // cannot open input NOUSER = 67, // addressee unknown NOHOST = 68, // host name unknown UNAVAILABLE = 69, // service unavailable SOFTWARE = 70, // internal software error OSERR = 71, // system error (e.g., can't fork) OSFILE = 72, // critical OS file missing CANTCREAT = 73, // can't create (user) output file IOERR = 74, // input/output error TEMPFAIL = 75, // temp failure; user is invited to retry PROTOCOL = 76, // remote error in protocol NOPERM = 77, // permission denied CONFIG = 78 // configuration error }; class Name: public NoCopy { optional shortName_; string longName_; optional description_; public: Name(string longName) : longName_("--" + longName) {} Name(string longName, string description) : longName_("--" + longName), description_(move(description)) {} Name(char shortName, string longName) : shortName_("-"), longName_("--" + longName) { shortName_->push_back(shortName); } Name(char shortName, string longName, string description) : shortName_("-"), longName_("--" + longName), description_(move(description)) { shortName_->push_back(shortName); } template void forEachName(Functor&& functor) const { if (shortName_) { functor(*shortName_); } functor(longName_); } bool anyMatch(const char* arg) const { if (shortName_) { if (arg == *shortName_) { return true; } } return arg == longName_; } const string& longName() const { return longName_; } string makeNamesString() const { string result(" "); if (shortName_) { result += *shortName_ + ", "; } return result + longName_; } bool multiLineDescription(size_t width) const { return description_ && description_->size() > width; } void showDescription(Out output, size_t width, size_t padding) const { width = max(width, static_cast(10u)); if (description_) { auto current = description_->begin(); while (static_cast(description_->end() - current) > width) { auto currentEnd = current + static_cast(width); auto breakAt = currentEnd; while (true) { --breakAt; if (breakAt == current) { // We didn't find a space - hyphenate. --currentEnd; copy(current, currentEnd, ostream_iterator(*output)); *output << "-"; current = currentEnd; break; } if (*breakAt == ' ') { copy(current, breakAt, ostream_iterator(*output)); current = breakAt; break; } } *output << "\n"; fill_n(ostream_iterator(*output), padding, ' '); while (*current == ' ') { ++current; } } copy(current, description_->end(), ostream_iterator(*output)); } *output << "\n"; } }; template class Option final { Name name_; string valueName_; optional defaultValue_; public: using Value = ValueType; Option(Name name, string valueName) : name_(move(name)), valueName_(move(valueName)) {} Option(Name name, string valueName, string defaultValue) : name_(move(name)), valueName_(move(valueName)), defaultValue_(move(defaultValue)) {} template void forEachName(Functor&& functor) const { name_.forEachName(forward(functor)); } bool anyMatch(const char* arg) const { return name_.anyMatch(arg); } const string& longName() const { return name_.longName(); } string makeNamesString() const { return name_.makeNamesString() + " <" + valueName_ + ">"; } bool multiLineDescription(size_t width) const { return name_.multiLineDescription(width); } void showDescription(Out output, size_t width, size_t padding) const { name_.showDescription(output, width, padding); } optional defaultValue() const { return defaultValue_; } }; class Flag final: public Name { public: using Name::Name; }; enum class ParamType { OPTION, FLAG }; class Arguments final : public NoCopy { Out helpOut_; Out errorOut_; string description_; string notes_; string version_; string positionalDescription_; size_t terminalWidth_; static const Flag& helpFlag() { static const Flag instance{"help", "Display this help message."}; return instance; } static const Flag& versionFlag() { static const Flag instance{"version", "Display version information."}; return instance; } template void displayHelp( const char *exeName, Params&&... params ) { *helpOut_ << "Usage: " << exeName << " [OPTION]..."; if ( ! positionalDescription_.empty()) { *helpOut_ << " [" << positionalDescription_ << "]..."; } *helpOut_ << "\n\n"; if ( ! description_.empty()) { *helpOut_ << description_ << "\n\n"; } size_t padding = 0; mapParameterPack( [this, &padding](const auto &arg) { padding = max(arg.makeNamesString().size(), padding); }, params..., helpFlag(), versionFlag() ); constexpr const size_t tabWidth = 4; padding += tabWidth; padding = makeDivisibleByRoundingUp(padding, tabWidth); padding = min(terminalWidth_ / 2, padding); mapParameterPack( [this, padding, tabWidth](const auto &arg) { auto nameString = arg.makeNamesString(); *helpOut_ << nameString; size_t currentPadding = padding; bool descriptionOnNewline = nameString.size() + tabWidth > padding; if (descriptionOnNewline) { *helpOut_ << "\n"; } else { currentPadding -= nameString.size(); } fill_n(ostream_iterator(*helpOut_), currentPadding, ' '); auto descriptionWidth = terminalWidth_ - padding; arg.showDescription(helpOut_, descriptionWidth, padding); if (descriptionOnNewline || arg.multiLineDescription(descriptionWidth)) { *helpOut_ << "\n"; } }, params..., helpFlag(), versionFlag() ); *helpOut_ << "\n"; if ( ! notes_.empty()) { *helpOut_ << notes_ << "\n\n"; } } template ExitStatus runImpl( map> optionValues, vector positionalArgs, set setFlags, Functor&& functor ) { return functor(move(positionalArgs)); } template ExitStatus runImpl( map> optionValues, vector positionalArgs, set setFlags, Functor&& functor, Option&& param, ParamTail&&... paramTail ) { vector paramValues; param.forEachName([&] (const string& name) { const auto& newValues = optionValues[name]; paramValues.insert(paramValues.end(), newValues.begin(), newValues.end()); }); string value; if (paramValues.empty()) { if (param.defaultValue()) { value = *param.defaultValue(); } else { *errorOut_ << "Error: No value for " + param.longName() << "\n"; return ExitStatus::CONFIG; } } else { value = paramValues.front(); } if (paramValues.size() > 1) { *errorOut_ << "Error: Multiple values for " + param.longName() << "\n"; return ExitStatus::CONFIG; } return runImpl( move(optionValues), move(positionalArgs), move(setFlags), bindFirst( forward(functor), move(value), index_sequence_for, ParamTail...>() ), forward(paramTail)... ); } template ExitStatus runImpl( map> optionValues, vector positionalArgs, set setFlags, Functor&& functor, Option>&& param, ParamTail&&... paramTail ) { vector paramValues; param.forEachName([&] (const string& name) { const auto& newValues = optionValues[name]; paramValues.insert(paramValues.end(), newValues.begin(), newValues.end()); }); return runImpl( move(optionValues), move(positionalArgs), move(setFlags), bindFirst( forward(functor), move(paramValues), index_sequence_for, ParamTail...>() ), forward(paramTail)... ); } template ExitStatus runImpl( map> optionValues, vector positionalArgs, set setFlags, Functor&& functor, Flag&& flag, ParamTail&&... paramTail ) { bool flagValue = false; flag.forEachName([&] (const string& name) { flagValue |= setFlags.count(name) > 0; }); return runImpl( move(optionValues), move(positionalArgs), move(setFlags), bindFirst( forward(functor), flagValue, index_sequence_for() ), forward(paramTail)... ); } template void readNamesImpl( Out> optionNames, Out> allNames, const Option& option, const ParamsTail&... paramsTail ) { option.forEachName([&] (const string& name) { optionNames->emplace(name); }); readNames(optionNames, allNames, paramsTail...); } template void readNamesImpl( Out> optionNames, Out> allNames, const Flag& flag, const ParamsTail&... paramsTail ) { readNames(optionNames, allNames, paramsTail...); } void readNames(Out> optionNames, Out> allNames) {} template void readNames( Out> optionNames, Out> allNames, const ParamType& param, const ParamsTail&... paramsTail ) { param.forEachName([&] (const string& name) { if ( ! allNames->emplace(name).second) { throw logic_error("Duplicate name " + name); } }); readNamesImpl(optionNames, allNames, param, paramsTail...); } enum class StandardArg { NONE, HELP, VERSION }; StandardArg checkArgs(int argc, const char* const argv[]) { if (argc <= 0) { throw runtime_error("argc is 0."); } else if (argv == nullptr) { throw runtime_error("argv is null."); } else { for (int index = 0; index < argc; ++index) { if (argv[index] == nullptr) { throw runtime_error("argv has null value."); } else { if (helpFlag().anyMatch(argv[index])) { return StandardArg::HELP; } if (versionFlag().anyMatch(argv[index])) { return StandardArg::VERSION; } } } } return StandardArg::NONE; } template ExitStatus runImpl( int argc, const char* const argv[], Functor &&functor, Params&&... params ) { auto standardArg = checkArgs(argc, argv); if (standardArg == StandardArg::HELP) { displayHelp(argv[0], forward(params)...); return ExitStatus::OK; } if (standardArg == StandardArg::VERSION) { *helpOut_ << version_ << "\n"; return ExitStatus::OK; } set optionNames; set allNames; readNames(out(optionNames), out(allNames), params...); map> optionValues; vector positionalArgs; set setFlags; for (int index = 1; index < argc; ++index) { string currentArg(argv[index]); if (currentArg == "--") { positionalArgs.insert(positionalArgs.end(), argv + index, argv + argc); break; } if ( ! currentArg.empty() && currentArg[0] == '-') { if (allNames.count(currentArg) == 0) { *errorOut_<< "Error: Unknown option " << currentArg << "\n"; return ExitStatus::USAGE; } if (optionNames.count(currentArg)) { ++index; if (index == argc) { *errorOut_<< "Error: No value supplied for option " << currentArg << "\n"; return ExitStatus::USAGE; } optionValues[currentArg].emplace_back(argv[index]); } else { setFlags.emplace(currentArg); } } else { positionalArgs.emplace_back(currentArg); } } return runImpl( move(optionValues), move(positionalArgs), move(setFlags), forward(functor), forward(params)... ); } const char* exeName(int argc, const char* const argv[]) { if (argv && argc > 0 && argv[0]) { return argv[0]; } return "unknown"; } public: Arguments(Out helpOut, Out errorOut, string version, size_t terminalWidth = 80) : helpOut_(helpOut), errorOut_(errorOut), version_(move(version)), terminalWidth_(terminalWidth) {} void setDescription(string description) { description_ = move(description); } void setNotes(string notes) { notes_ = move(notes); } void setPositionalDescription(string positionalDescription) { positionalDescription_ = move(positionalDescription); } Arguments(string version, size_t terminalWidth = 80) : Arguments(out(cout), out(cerr), move(version), terminalWidth) {} template int run( int argc, const char* const argv[], Functor &&functor, Params&&... params ) { try { return static_cast(runImpl(argc, argv, forward(functor), forward(params)...)); } catch (const exception& e) { *errorOut_ << exeName(argc, argv) << ": " << e.what() << "\n"; } return static_cast(ExitStatus::SOFTWARE); } }; }}}} namespace Enhedron { namespace CommandLine { using Impl::Impl_Parameters::ExitStatus; using Impl::Impl_Parameters::Arguments; using Impl::Impl_Parameters::Option; using Impl::Impl_Parameters::Flag; using Impl::Impl_Parameters::Name; }} // File: Enhedron/Test/Harness.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include #include #include #include #include #include namespace Enhedron { namespace Test { namespace Impl { namespace Impl_Harness { using std::string; using std::move; using std::vector; using std::shared_ptr; using std::make_shared; using std::runtime_error; using std::find_first_of; using std::tolower; using std::locale; using std::transform; using std::regex; using CommandLine::ExitStatus; using CommandLine::Flag; using CommandLine::Option; using CommandLine::Name; using CommandLine::Arguments; inline Verbosity parseVerbosity(string v) { transform(v.begin(), v.end(), v.begin(), [](char c) { return tolower(c, locale()); } ); if (v == "silent") return Verbosity::SILENT; if (v == "summary") return Verbosity::SUMMARY; if (v == "contexts") return Verbosity::CONTEXTS; if (v == "fixtures") return Verbosity::FIXTURES; if (v == "sections") return Verbosity::SECTIONS; if (v == "exhaustive_sections") return Verbosity::EXHAUSTIVE_SECTIONS; if (v == "checks") return Verbosity::CHECKS; if (v == "checks_expression") return Verbosity::CHECKS_EXPRESSION; if (v == "variables") return Verbosity::VARIABLES; throw runtime_error("Unknown verbosity \"" + v + "\""); } inline ExitStatus runTests(bool listOnly, string verbosityString, vector pathList) { vector>> pathRegexs; for (auto& path : pathList) { vector pathComponentList; auto separatorPos = path.begin(); auto matchChars = "/\\"; auto matchCharsEnd = matchChars + 2; auto pathEnd = path.end(); while (true) { auto end = find_first_of(separatorPos, pathEnd, matchChars, matchCharsEnd); while (end != pathEnd && end + 1 != pathEnd && *end == '\\') { ++end; if (*end == '/') { copy(end, pathEnd, end - 1); } else { ++end; } end = find_first_of(end, pathEnd, matchChars, matchCharsEnd); } if (separatorPos != end) { pathComponentList.emplace_back(separatorPos, end); } if (end == pathEnd) { break; } separatorPos = end; ++separatorPos; } pathRegexs.emplace_back(make_shared>(move(pathComponentList))); } Verbosity verbosity = parseVerbosity(verbosityString); if (listOnly) { Test::list(pathRegexs, verbosity); } else { if ( ! Test::run(pathRegexs, verbosity)) { return ExitStatus::SOFTWARE; } } return ExitStatus::OK; } inline int run(int argc, const char* argv[]) { Arguments args("MosquitoNet test harness version 0.0.0"); args.setDescription("Test Harness"); args.setPositionalDescription("TEST_PATH"); return args.run( argc, argv, runTests, Flag('l', "list", "List tests instead of running them."), Option(Name('v', "verbosity", "Set the verbosity"), "silent|summary|contexts|fixtures|sections|exhaustive-sections|checks_description|checks_expression|variables", "contexts" ) ); } }}}} namespace Enhedron { namespace Test { using Impl::Impl_Harness::run; }} // File: Enhedron/Assertion/Functions.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #include #include #include namespace Enhedron { namespace Assertion { namespace Impl { namespace Impl_Functions { using std::forward; using std::count; using std::count_if; using std::equal; using std::all_of; using std::any_of; using std::none_of; using std::search; using std::remove_reference_t; template auto countEqual(Container&& container, Value&& value) { return makeFunction( "countEqual", [] (auto&& container, auto&& value) { return count(container.begin(), container.end(), forward(value)); } )(forward(container), forward(value)); } template auto countMatching(Container&& container, Predicate&& predicate) { return makeFunction( "countMatching", [] (auto&& container, auto&& predicate) { return count_if(container.begin(), container.end(), forward(predicate)); } )(forward(container), forward(predicate)); } template auto allOf(Container&& container, Predicate&& predicate) { return makeFunction( "allOf", [] (auto&& container, auto&& predicate) { return all_of(container.begin(), container.end(), forward(predicate)); } )(forward(container), forward(predicate)); } template auto anyOf(Container&& container, Predicate&& predicate) { return makeFunction( "anyOf", [] (auto&& container, auto&& predicate) { return any_of(container.begin(), container.end(), forward(predicate)); } )(forward(container), forward(predicate)); } template auto noneOf(Container&& container, Predicate&& predicate) { return makeFunction( "noneOf", [] (auto&& container, auto&& predicate) { return none_of(container.begin(), container.end(), forward(predicate)); } )(forward(container), forward(predicate)); } template auto length(Container&& container) { return makeFunction( "length", [] (auto&& container) { return container.size(); } )(forward(container)); } template auto startsWith(MainContainer&& container, StartsWithContainer&& starting) { return makeFunction( "startsWith", [] (auto&& container, auto&& starting) { return container.size() >= starting.size() && equal(starting.begin(), starting.end(), container.begin()); } )(forward(container), forward(starting)); } template auto endsWith(MainContainer&& container, EndsWithContainer&& ending) { return makeFunction( "endsWith", [] (auto&& container, auto&& ending) { using ContainerType = remove_reference_t; auto size = static_cast(ending.size()); return container.size() >= ending.size() && equal(ending.begin(), ending.end(), container.end() - size); } )(forward(container), forward(ending)); } template auto contains(MainContainer&& mainContainer, Contained&& contained) { return makeFunction( "contains", [] (auto&& mainContainer, auto&& contained) { return mainContainer.end() != search(mainContainer.begin(), mainContainer.end(), contained.begin(), contained.end()); } )(forward(mainContainer), forward(contained)); } }}}} namespace Enhedron { namespace Assertion { using Impl::Impl_Functions::countEqual; using Impl::Impl_Functions::countMatching; using Impl::Impl_Functions::allOf; using Impl::Impl_Functions::anyOf; using Impl::Impl_Functions::noneOf; using Impl::Impl_Functions::length; using Impl::Impl_Functions::startsWith; using Impl::Impl_Functions::endsWith; using Impl::Impl_Functions::contains; }} // File: Enhedron/Test.h // // Copyright Simon Bourne 2015. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // #endif /* ENHEDRON_MOSQUITONET_H_ */