Merge pull request #110 from baylesj/remote_throws

Add VALIJSON_USE_EXCEPTIONS mode
This commit is contained in:
Tristan Penman 2020-11-09 16:51:19 +11:00 committed by GitHub
commit c1e75c700f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 350 additions and 154 deletions

View File

@ -7,6 +7,7 @@ option(valijson_INSTALL_HEADERS "Install valijson headers." FALSE)
option(valijson_BUILD_EXAMPLES "Build valijson examples." FALSE) option(valijson_BUILD_EXAMPLES "Build valijson examples." FALSE)
option(valijson_BUILD_TESTS "Build valijson test suite." TRUE) option(valijson_BUILD_TESTS "Build valijson test suite." TRUE)
option(valijson_EXCLUDE_BOOST "Exclude Boost when building test suite." FALSE) option(valijson_EXCLUDE_BOOST "Exclude Boost when building test suite." FALSE)
option(valijson_USE_EXCEPTIONS "Use exceptions in valijson and included libs." TRUE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
@ -38,6 +39,16 @@ else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif() endif()
#TODO()
if(valijson_USE_EXCEPTIONS)
add_definitions(-DVALIJSON_USE_EXCEPTIONS=1)
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
add_definitions(-DBOOST_NO_EXCEPTIONS)
add_definitions(-DJSON_USE_EXCEPTION=0)
add_definitions(-DVALIJSON_USE_EXCEPTIONS=0)
endif()
find_package(curlpp) find_package(curlpp)
find_package(Poco OPTIONAL_COMPONENTS JSON) find_package(Poco OPTIONAL_COMPONENTS JSON)
find_package(Qt5Core) find_package(Qt5Core)

View File

@ -17,6 +17,7 @@
# include <functional> # include <functional>
# include <string> # include <string>
# include <stdexcept> # include <stdexcept>
# include <valijson/exceptions.hpp>
# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false # define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false
@ -523,15 +524,15 @@ namespace std{
} }
constexpr T const& value() const& { constexpr T const& value() const& {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
} }
OPTIONAL_MUTABLE_CONSTEXPR T& value() & { OPTIONAL_MUTABLE_CONSTEXPR T& value() & {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
} }
OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { OPTIONAL_MUTABLE_CONSTEXPR T&& value() && {
if (!initialized()) throw bad_optional_access("bad optional access"); if (!initialized()) valijson::throwRuntimeError("bad optional access");
return std::move(contained_val()); return std::move(contained_val());
} }
@ -552,11 +553,11 @@ namespace std{
} }
constexpr T const& value() const { constexpr T const& value() const {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
} }
T& value() { T& value() {
return initialized() ? contained_val() : (throw bad_optional_access("bad optional access"), contained_val()); return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val());
} }
# endif # endif
@ -685,7 +686,7 @@ namespace std{
} }
constexpr T& value() const { constexpr T& value() const {
return ref ? *ref : (throw bad_optional_access("bad optional access"), *ref); return ref ? *ref : (valijson::throwRuntimeError("bad optional access"), *ref);
} }
explicit constexpr operator bool() const noexcept { explicit constexpr operator bool() const noexcept {

View File

@ -5,6 +5,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/internal/optional.hpp> #include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -297,7 +298,7 @@ public:
} }
} }
throw std::runtime_error("JSON value cannot be cast to an array."); throwRuntimeError("JSON value cannot be cast to an array.");
} }
bool asBool() const override bool asBool() const override
@ -307,7 +308,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value cannot be cast to a boolean."); throwRuntimeError("JSON value cannot be cast to a boolean.");
} }
bool asBool(bool &result) const override bool asBool(bool &result) const override
@ -337,7 +338,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value cannot be cast to a double."); throwRuntimeError("JSON value cannot be cast to a double.");
} }
bool asDouble(double &result) const override bool asDouble(double &result) const override
@ -374,7 +375,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value cannot be cast as an integer."); throwRuntimeError("JSON value cannot be cast as an integer.");
} }
bool asInteger(int64_t &result) const override bool asInteger(int64_t &result) const override
@ -425,7 +426,7 @@ public:
} }
} }
throw std::runtime_error("JSON value cannot be cast to an object."); throwRuntimeError("JSON value cannot be cast to an object.");
} }
std::string asString() const override std::string asString() const override
@ -435,7 +436,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value cannot be cast to a string."); throwRuntimeError("JSON value cannot be cast to a string.");
} }
bool asString(std::string &result) const override bool asString(std::string &result) const override
@ -541,7 +542,7 @@ public:
return *arrayValue; return *arrayValue;
} }
throw std::runtime_error("JSON value is not an array."); throwRuntimeError("JSON value is not an array.");
} }
size_t getArraySize() const override size_t getArraySize() const override
@ -551,7 +552,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not an array."); throwRuntimeError("JSON value is not an array.");
} }
bool getArraySize(size_t &result) const override bool getArraySize(size_t &result) const override
@ -566,7 +567,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not a boolean."); throwRuntimeError("JSON value is not a boolean.");
} }
bool getBool(bool &result) const override bool getBool(bool &result) const override
@ -581,7 +582,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not a double."); throwRuntimeError("JSON value is not a double.");
} }
bool getDouble(double &result) const override bool getDouble(double &result) const override
@ -596,7 +597,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not an integer."); throwRuntimeError("JSON value is not an integer.");
} }
bool getInteger(int64_t &result) const override bool getInteger(int64_t &result) const override
@ -611,7 +612,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not a number."); throwRuntimeError("JSON value is not a number.");
} }
bool getNumber(double &result) const override bool getNumber(double &result) const override
@ -650,7 +651,7 @@ public:
return *objectValue; return *objectValue;
} }
throw std::runtime_error("JSON value is not an object."); throwRuntimeError("JSON value is not an object.");
} }
size_t getObjectSize() const override size_t getObjectSize() const override
@ -660,7 +661,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not an object."); throwRuntimeError("JSON value is not an object.");
} }
bool getObjectSize(size_t &result) const override bool getObjectSize(size_t &result) const override
@ -675,7 +676,7 @@ public:
return result; return result;
} }
throw std::runtime_error("JSON value is not a string."); throwRuntimeError("JSON value is not a string.");
} }
bool getString(std::string &result) const override bool getString(std::string &result) const override

View File

@ -31,6 +31,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -76,7 +77,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.is_array()) { if (!value.is_array()) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -154,7 +155,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.is_object()) { if (!value.is_object()) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }

View File

@ -34,6 +34,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -78,7 +79,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.isArray()) { if (!value.isArray()) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -156,7 +157,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.isObject()) { if (!value.isObject()) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }

View File

@ -31,6 +31,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/exceptions.hpp>
#include <utility> #include <utility>
namespace valijson { namespace valijson {
@ -77,7 +78,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.is_array()) { if (!value.is_array()) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -155,7 +156,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.is_object()) { if (!value.is_object()) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }

View File

@ -32,6 +32,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -77,7 +78,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.is<picojson::array>()) { if (!value.is<picojson::array>()) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -156,7 +157,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.is<picojson::object>()) { if (!value.is<picojson::object>()) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }

View File

@ -31,6 +31,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -77,7 +78,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (value.type() != typeid(Poco::JSON::Array::Ptr)) { if (value.type() != typeid(Poco::JSON::Array::Ptr)) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -154,7 +155,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (value.type() != typeid(Poco::JSON::Object::Ptr)) { if (value.type() != typeid(Poco::JSON::Object::Ptr)) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }

View File

@ -26,6 +26,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <utility>
#include <QJsonObject> #include <QJsonObject>
#include <QJsonValue> #include <QJsonValue>
@ -34,7 +35,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <utility> #include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -82,7 +83,7 @@ public:
: m_value(value.toArray()) : m_value(value.toArray())
{ {
if (!value.isArray()) { if (!value.isArray()) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -162,7 +163,7 @@ public:
: m_value(value.toObject()) : m_value(value.toObject())
{ {
if (!value.isObject()) { if (!value.isObject()) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }

View File

@ -48,6 +48,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -112,7 +113,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.IsArray()) { if (!value.IsArray()) {
throw std::runtime_error("Value is not an array."); throwRuntimeError("Value is not an array.");
} }
} }
@ -181,7 +182,7 @@ public:
: m_value(value) : m_value(value)
{ {
if (!value.IsObject()) { if (!value.IsObject()) {
throw std::runtime_error("Value is not an object."); throwRuntimeError("Value is not an object.");
} }
} }
@ -270,7 +271,7 @@ public:
explicit GenericRapidJsonFrozenValue(const ValueType &source) explicit GenericRapidJsonFrozenValue(const ValueType &source)
{ {
if (!copy(source, m_value, m_allocator)) { if (!copy(source, m_value, m_allocator)) {
throw std::runtime_error("Failed to copy ValueType"); throwRuntimeError("Failed to copy ValueType");
} }
} }

View File

@ -19,6 +19,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/adapters/frozen_value.hpp> #include <valijson/adapters/frozen_value.hpp>
#include <valijson/adapters/basic_adapter.hpp> #include <valijson/adapters/basic_adapter.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace adapters { namespace adapters {
@ -110,7 +111,7 @@ public:
return {}; return {};
} }
throw std::runtime_error("String value cannot be cast to array"); throwRuntimeError("String value cannot be cast to array");
} }
bool asBool() const override bool asBool() const override
@ -152,7 +153,7 @@ public:
return {}; return {};
} }
throw std::runtime_error("String value cannot be cast to object"); throwRuntimeError("String value cannot be cast to object");
} }
std::string asString() const override std::string asString() const override
@ -182,67 +183,67 @@ public:
static StdStringArray getArray() static StdStringArray getArray()
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
size_t getArraySize() const override size_t getArraySize() const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getArraySize(size_t &) const override bool getArraySize(size_t &) const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getBool() const override bool getBool() const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getBool(bool &) const override bool getBool(bool &) const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
double getDouble() const override double getDouble() const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getDouble(double &) const override bool getDouble(double &) const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
int64_t getInteger() const override int64_t getInteger() const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getInteger(int64_t &) const override bool getInteger(int64_t &) const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
double getNumber() const override double getNumber() const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getNumber(double &) const override bool getNumber(double &) const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
size_t getObjectSize() const override size_t getObjectSize() const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool getObjectSize(size_t &) const override bool getObjectSize(size_t &) const override
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
std::string getString() const override std::string getString() const override
@ -355,12 +356,12 @@ class StdStringArrayValueIterator: public std::iterator<std::bidirectional_itera
public: public:
StdStringAdapter operator*() const StdStringAdapter operator*() const
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
DerefProxy<StdStringAdapter> operator->() const DerefProxy<StdStringAdapter> operator->() const
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool operator==(const StdStringArrayValueIterator &) const bool operator==(const StdStringArrayValueIterator &) const
@ -375,22 +376,22 @@ public:
const StdStringArrayValueIterator& operator++() const StdStringArrayValueIterator& operator++()
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
StdStringArrayValueIterator operator++(int) StdStringArrayValueIterator operator++(int)
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
const StdStringArrayValueIterator& operator--() const StdStringArrayValueIterator& operator--()
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
void advance(std::ptrdiff_t) void advance(std::ptrdiff_t)
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
}; };
@ -409,12 +410,12 @@ class StdStringObjectMemberIterator: public std::iterator<std::bidirectional_ite
public: public:
StdStringObjectMember operator*() const StdStringObjectMember operator*() const
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
DerefProxy<StdStringObjectMember> operator->() const DerefProxy<StdStringObjectMember> operator->() const
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
bool operator==(const StdStringObjectMemberIterator &) const bool operator==(const StdStringObjectMemberIterator &) const
@ -429,17 +430,17 @@ public:
const StdStringObjectMemberIterator& operator++() const StdStringObjectMemberIterator& operator++()
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
StdStringObjectMemberIterator operator++(int) StdStringObjectMemberIterator operator++(int)
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
const StdStringObjectMemberIterator& operator--() const StdStringObjectMemberIterator& operator--()
{ {
throw std::runtime_error("Not supported"); throwNotSupported();
} }
}; };

View File

@ -2,8 +2,8 @@
#include <valijson/constraints/constraint.hpp> #include <valijson/constraints/constraint.hpp>
#include <valijson/constraints/constraint_visitor.hpp> #include <valijson/constraints/constraint_visitor.hpp>
#include <valijson/internal/custom_allocator.hpp> #include <valijson/internal/custom_allocator.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace constraints { namespace constraints {
@ -40,7 +40,7 @@ struct BasicConstraint: Constraint
{ {
void *ptr = allocFn(sizeof(ConstraintType)); void *ptr = allocFn(sizeof(ConstraintType));
if (!ptr) { if (!ptr) {
throw std::runtime_error("Failed to allocate memory for cloned constraint"); throwRuntimeError("Failed to allocate memory for cloned constraint");
} }
return new (ptr) ConstraintType(*static_cast<const ConstraintType*>(this)); return new (ptr) ConstraintType(*static_cast<const ConstraintType*>(this));

View File

@ -24,6 +24,7 @@
#include <valijson/constraints/basic_constraint.hpp> #include <valijson/constraints/basic_constraint.hpp>
#include <valijson/internal/custom_allocator.hpp> #include <valijson/internal/custom_allocator.hpp>
#include <valijson/schema.hpp> #include <valijson/schema.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
@ -296,7 +297,7 @@ public:
return *this; return *this;
} }
throw std::runtime_error("Dependencies constraint already contains a dependent " throwRuntimeError("Dependencies constraint already contains a dependent "
"schema for the property '" + propertyName + "'"); "schema for the property '" + propertyName + "'");
} }
@ -357,12 +358,17 @@ public:
: BasicConstraint(other), : BasicConstraint(other),
m_enumValues(Allocator::rebind<const EnumValue *>::other(m_allocator)) m_enumValues(Allocator::rebind<const EnumValue *>::other(m_allocator))
{ {
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
// Clone individual enum values // Clone individual enum values
for (const EnumValue *otherValue : other.m_enumValues) { for (const EnumValue *otherValue : other.m_enumValues) {
const EnumValue *value = otherValue->clone(); const EnumValue *value = otherValue->clone();
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
m_enumValues.push_back(value); m_enumValues.push_back(value);
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
delete value; delete value;
value = nullptr; value = nullptr;
@ -375,6 +381,7 @@ public:
delete value; delete value;
} }
throw; throw;
#endif
} }
} }
@ -895,15 +902,19 @@ public:
{ {
void *ptr = allocFn(sizeOf()); void *ptr = allocFn(sizeOf());
if (!ptr) { if (!ptr) {
throw std::runtime_error("Failed to allocate memory for cloned constraint"); throwRuntimeError("Failed to allocate memory for cloned constraint");
} }
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
return cloneInto(ptr); return cloneInto(ptr);
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
freeFn(ptr); freeFn(ptr);
throw; throw;
} }
#endif
} }
virtual bool validate(const adapters::Adapter &target, virtual bool validate(const adapters::Adapter &target,
@ -1190,8 +1201,9 @@ public:
return kString; return kString;
} }
throw std::runtime_error("Unrecognised JSON type name '" + throwRuntimeError("Unrecognised JSON type name '" +
std::string(typeName.c_str()) + "'"); std::string(typeName.c_str()) + "'");
abort();
} }
private: private:

View File

@ -0,0 +1,41 @@
#pragma once
#include <iostream>
#include <exception>
namespace valijson {
#if defined(_MSC_VER) && _MSC_VER == 1800
#define VALIJSON_NORETURN __declspec(noreturn)
#else
#define VALIJSON_NORETURN [[noreturn]]
#endif
#if VALIJSON_USE_EXCEPTIONS
#include <stdexcept>
VALIJSON_NORETURN inline void throwRuntimeError(const std::string& msg) {
throw std::runtime_error(msg);
}
VALIJSON_NORETURN inline void throwLogicError(const std::string& msg) {
throw std::logic_error(msg);
}
#else
VALIJSON_NORETURN inline void throwRuntimeError(const std::string& msg) {
std::cerr << msg << std::endl;
abort();
}
VALIJSON_NORETURN inline void throwLogicError(const std::string& msg) {
std::cerr << msg << std::endl;
abort();
}
#endif
VALIJSON_NORETURN inline void throwNotSupported() {
throwRuntimeError("Not supported"); \
}
} // namespace valijson

View File

@ -9,6 +9,7 @@
#include <valijson/adapters/adapter.hpp> #include <valijson/adapters/adapter.hpp>
#include <valijson/internal/optional.hpp> #include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace internal { namespace internal {
@ -43,7 +44,7 @@ inline void replaceAllInPlace(std::string& subject, const char* search,
inline char decodePercentEncodedChar(const std::string &digits) inline char decodePercentEncodedChar(const std::string &digits)
{ {
if (digits.length() != 2) { if (digits.length() != 2) {
throw std::runtime_error("Failed to decode %-encoded character '" + throwRuntimeError("Failed to decode %-encoded character '" +
digits + "' due to unexpected number of characters; " digits + "' due to unexpected number of characters; "
"expected two characters"); "expected two characters");
} }
@ -53,7 +54,7 @@ inline char decodePercentEncodedChar(const std::string &digits)
char *end = nullptr; char *end = nullptr;
const unsigned long value = strtoul(begin, &end, 16); const unsigned long value = strtoul(begin, &end, 16);
if (end != begin && *end != '\0') { if (end != begin && *end != '\0') {
throw std::runtime_error("Failed to decode %-encoded character '" + throwRuntimeError("Failed to decode %-encoded character '" +
digits + "'"); digits + "'");
} }
@ -101,14 +102,17 @@ inline std::string extractReferenceToken(std::string::const_iterator begin,
for (size_t n = token.find('%'); n != std::string::npos; for (size_t n = token.find('%'); n != std::string::npos;
n = token.find('%', n + 1)) { n = token.find('%', n + 1)) {
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
const char c = decodePercentEncodedChar(token.substr(n + 1, 2)); const char c = decodePercentEncodedChar(token.substr(n + 1, 2));
token.replace(n, 3, &c, 1); token.replace(n, 3, &c, 1);
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
throw std::runtime_error( throwRuntimeError(
std::string(e.what()) + "; in token: " + token); std::string(e.what()) + "; in token: " + token);
} }
#endif
} }
return token; return token;
@ -159,7 +163,7 @@ inline AdapterType resolveJsonPointer(
// Reference tokens must begin with a leading slash // Reference tokens must begin with a leading slash
if (*jsonPointerItr != '/') { if (*jsonPointerItr != '/') {
throw std::runtime_error("Expected reference token to begin with " throwRuntimeError("Expected reference token to begin with "
"leading slash; remaining tokens: " + "leading slash; remaining tokens: " +
std::string(jsonPointerItr, jsonPointerEnd)); std::string(jsonPointerItr, jsonPointerEnd));
} }
@ -179,24 +183,26 @@ inline AdapterType resolveJsonPointer(
} else if (node.isArray()) { } else if (node.isArray()) {
if (referenceToken == "-") { if (referenceToken == "-") {
throw std::runtime_error("Hyphens cannot be used as array indices " throwRuntimeError("Hyphens cannot be used as array indices "
"since the requested array element does not yet exist"); "since the requested array element does not yet exist");
} }
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
// Fragment must be non-negative integer // Fragment must be non-negative integer
const uint64_t index = std::stoul(referenceToken); const uint64_t index = std::stoul(referenceToken);
typedef typename AdapterType::Array Array; typedef typename AdapterType::Array Array;
typename Array::const_iterator itr = node.asArray().begin(); typename Array::const_iterator itr = node.asArray().begin();
if (index > node.asArray().size() - 1) { if (index > node.asArray().size() - 1) {
throw std::runtime_error("Expected reference token to identify " throwRuntimeError("Expected reference token to identify "
"an element in the current array, but array index is " "an element in the current array, but array index is "
"out of bounds; actual token: " + referenceToken); "out of bounds; actual token: " + referenceToken);
} }
if (index > static_cast<uint64_t>(std::numeric_limits<std::ptrdiff_t>::max())) { if (index > static_cast<uint64_t>(std::numeric_limits<std::ptrdiff_t>::max())) {
throw std::runtime_error("Array index out of bounds; hard " throwRuntimeError("Array index out of bounds; hard "
"limit is " + std::to_string( "limit is " + std::to_string(
std::numeric_limits<std::ptrdiff_t>::max())); std::numeric_limits<std::ptrdiff_t>::max()));
} }
@ -206,12 +212,13 @@ inline AdapterType resolveJsonPointer(
// Recursively process the remaining tokens // Recursively process the remaining tokens
return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext); return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext);
#if VALIJSON_USE_EXCEPTIONS
} catch (std::invalid_argument &) { } catch (std::invalid_argument &) {
throw std::runtime_error("Expected reference token to contain a " throwRuntimeError("Expected reference token to contain a "
"non-negative integer to identify an element in the " "non-negative integer to identify an element in the "
"current array; actual token: " + referenceToken); "current array; actual token: " + referenceToken);
} }
#endif
} else if (node.maybeObject()) { } else if (node.maybeObject()) {
// Fragment must identify a member of the candidate object // Fragment must identify a member of the candidate object
typedef typename AdapterType::Object Object; typedef typename AdapterType::Object Object;
@ -220,18 +227,20 @@ inline AdapterType resolveJsonPointer(
typename Object::const_iterator itr = object.find( typename Object::const_iterator itr = object.find(
referenceToken); referenceToken);
if (itr == object.end()) { if (itr == object.end()) {
throw std::runtime_error("Expected reference token to identify an " throwRuntimeError("Expected reference token to identify an "
"element in the current object; " "element in the current object; "
"actual token: " + referenceToken); "actual token: " + referenceToken);
abort();
} }
// Recursively process the remaining tokens // Recursively process the remaining tokens
return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext); return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext);
} }
throw std::runtime_error("Expected end of JSON Pointer, but at least " throwRuntimeError("Expected end of JSON Pointer, but at least "
"one reference token has not been processed; remaining tokens: " + "one reference token has not been processed; remaining tokens: " +
std::string(jsonPointerNext, jsonPointerEnd)); std::string(jsonPointerNext, jsonPointerEnd));
abort();
} }
/** /**

View File

@ -4,6 +4,7 @@
#include <set> #include <set>
#include <valijson/subschema.hpp> #include <valijson/subschema.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
@ -53,15 +54,19 @@ public:
m_freeFn(const_cast<Subschema *>(sharedEmptySubschema)); m_freeFn(const_cast<Subschema *>(sharedEmptySubschema));
sharedEmptySubschema = nullptr; sharedEmptySubschema = nullptr;
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
for (auto subschema : subschemaSet) { for (auto subschema : subschemaSet) {
subschema->~Subschema(); subschema->~Subschema();
m_freeFn(subschema); m_freeFn(subschema);
} }
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::exception &e) { } catch (const std::exception &e) {
fprintf(stderr, "Caught an exception while destroying Schema: %s", fprintf(stderr, "Caught an exception while destroying Schema: %s",
e.what()); e.what());
} }
#endif
} }
/** /**
@ -92,17 +97,20 @@ public:
{ {
Subschema *subschema = newSubschema(); Subschema *subschema = newSubschema();
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
if (!subschemaSet.insert(subschema).second) { if (!subschemaSet.insert(subschema).second) {
throw std::runtime_error( throwRuntimeError(
"Failed to store pointer for new sub-schema"); "Failed to store pointer for new sub-schema");
} }
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
subschema->~Subschema(); subschema->~Subschema();
m_freeFn(subschema); m_freeFn(subschema);
throw; throw;
} }
#endif
return subschema; return subschema;
} }
@ -170,16 +178,20 @@ private:
{ {
void *ptr = m_allocFn(sizeof(Subschema)); void *ptr = m_allocFn(sizeof(Subschema));
if (!ptr) { if (!ptr) {
throw std::runtime_error( throwRuntimeError(
"Failed to allocate memory for shared empty sub-schema"); "Failed to allocate memory for shared empty sub-schema");
} }
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
return new (ptr) Subschema(); return new (ptr) Subschema();
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
m_freeFn(ptr); m_freeFn(ptr);
throw; throw;
} }
#endif
} }
Subschema * mutableSubschema(const Subschema *subschema) Subschema * mutableSubschema(const Subschema *subschema)
@ -189,13 +201,13 @@ private:
} }
if (subschema == sharedEmptySubschema) { if (subschema == sharedEmptySubschema) {
throw std::runtime_error( throwRuntimeError(
"Cannot modify the shared empty sub-schema"); "Cannot modify the shared empty sub-schema");
} }
auto *noConst = const_cast<Subschema*>(subschema); auto *noConst = const_cast<Subschema*>(subschema);
if (subschemaSet.find(noConst) == subschemaSet.end()) { if (subschemaSet.find(noConst) == subschemaSet.end()) {
throw std::runtime_error( throwRuntimeError(
"Subschema pointer is not owned by this Schema instance"); "Subschema pointer is not owned by this Schema instance");
} }

View File

@ -14,6 +14,7 @@
#include <valijson/internal/uri.hpp> #include <valijson/internal/uri.hpp>
#include <valijson/constraint_builder.hpp> #include <valijson/constraint_builder.hpp>
#include <valijson/schema.hpp> #include <valijson/schema.hpp>
#include <valijson/exceptions.hpp>
#ifdef __clang__ #ifdef __clang__
# pragma clang diagnostic push # pragma clang diagnostic push
@ -117,18 +118,22 @@ public:
typename FunctionPtrs<AdapterType>::FreeDoc freeDoc = nullptr ) typename FunctionPtrs<AdapterType>::FreeDoc freeDoc = nullptr )
{ {
if ((fetchDoc == nullptr ) ^ (freeDoc == nullptr)) { if ((fetchDoc == nullptr ) ^ (freeDoc == nullptr)) {
throw std::runtime_error("Remote document fetching can't be enabled without both fetch and free functions"); throwRuntimeError("Remote document fetching can't be enabled without both fetch and free functions");
} }
typename DocumentCache<AdapterType>::Type docCache; typename DocumentCache<AdapterType>::Type docCache;
SchemaCache schemaCache; SchemaCache schemaCache;
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
resolveThenPopulateSchema(schema, node, node, schema, opt::optional<std::string>(), "", fetchDoc, nullptr, resolveThenPopulateSchema(schema, node, node, schema, opt::optional<std::string>(), "", fetchDoc, nullptr,
nullptr, docCache, schemaCache); nullptr, docCache, schemaCache);
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
freeDocumentCache<AdapterType>(docCache, freeDoc); freeDocumentCache<AdapterType>(docCache, freeDoc);
throw; throw;
} }
#endif
freeDocumentCache<AdapterType>(docCache, freeDoc); freeDocumentCache<AdapterType>(docCache, freeDoc);
} }
@ -238,7 +243,7 @@ private:
if (itr == o.end()) { if (itr == o.end()) {
return false; return false;
} else if (!itr->second.asString(result)) { } else if (!itr->second.asString(result)) {
throw std::invalid_argument("$ref property expected to contain string value."); throwRuntimeError("$ref property expected to contain string value.");
} }
return true; return true;
@ -306,7 +311,7 @@ private:
for (const std::string &keyToCreate : keysToCreate) { for (const std::string &keyToCreate : keysToCreate) {
const SchemaCache::value_type value(keyToCreate, schema); const SchemaCache::value_type value(keyToCreate, schema);
if (!schemaCache.insert(value).second) { if (!schemaCache.insert(value).second) {
throw std::logic_error("Key '" + keyToCreate + "' already in schema cache."); throwLogicError("Key '" + keyToCreate + "' already in schema cache.");
} }
} }
} }
@ -423,7 +428,7 @@ private:
if (docCacheItr == docCache.end()) { if (docCacheItr == docCache.end()) {
// Resolve reference against remote document // Resolve reference against remote document
if (!fetchDoc) { if (!fetchDoc) {
throw std::runtime_error("Fetching of remote JSON References not enabled."); throwRuntimeError("Fetching of remote JSON References not enabled.");
} }
// Returns a pointer to the remote document that was // Returns a pointer to the remote document that was
@ -434,7 +439,7 @@ private:
// Can't proceed without the remote document // Can't proceed without the remote document
if (!newDoc) { if (!newDoc) {
throw std::runtime_error("Failed to fetch referenced schema document: " + *actualDocumentUri); throwRuntimeError("Failed to fetch referenced schema document: " + *actualDocumentUri);
} }
typedef typename DocumentCache<AdapterType>::Type::value_type typedef typename DocumentCache<AdapterType>::Type::value_type
@ -588,7 +593,7 @@ private:
s += " to contain schema object; actual node type is: "; s += " to contain schema object; actual node type is: ";
} }
s += internal::nodeTypeAsString(node); s += internal::nodeTypeAsString(node);
throw std::runtime_error(s); throwRuntimeError(s);
} }
} }
@ -650,7 +655,7 @@ private:
rootSchema.setSubschemaDescription(&subschema, rootSchema.setSubschemaDescription(&subschema,
itr->second.asString()); itr->second.asString());
} else { } else {
throw std::runtime_error( throwRuntimeError(
"'description' attribute should have a string value"); "'description' attribute should have a string value");
} }
} }
@ -666,11 +671,11 @@ private:
makeMultipleOfDoubleConstraint(itr->second), makeMultipleOfDoubleConstraint(itr->second),
&subschema); &subschema);
} else { } else {
throw std::runtime_error("Expected an numeric value for " throwRuntimeError("Expected an numeric value for "
" 'divisibleBy' constraint."); " 'divisibleBy' constraint.");
} }
} else { } else {
throw std::runtime_error( throwRuntimeError(
"'divisibleBy' constraint not valid after draft 3"); "'divisibleBy' constraint not valid after draft 3");
} }
} }
@ -722,7 +727,7 @@ private:
updatedScope, nodePath, fetchDoc, docCache, schemaCache), updatedScope, nodePath, fetchDoc, docCache, schemaCache),
&subschema); &subschema);
} else { } else {
throw std::runtime_error("Not supported"); throwRuntimeError("Not supported");
} }
} }
} }
@ -752,7 +757,7 @@ private:
&subschema); &subschema);
} }
} else if (object.find("exclusiveMaximum") != object.end()) { } else if (object.find("exclusiveMaximum") != object.end()) {
throw std::runtime_error("'exclusiveMaximum' constraint only valid if a 'maximum' " throwRuntimeError("'exclusiveMaximum' constraint only valid if a 'maximum' "
"constraint is also present"); "constraint is also present");
} }
@ -794,7 +799,7 @@ private:
&subschema); &subschema);
} }
} else if (object.find("exclusiveMinimum") != object.end()) { } else if (object.find("exclusiveMinimum") != object.end()) {
throw std::runtime_error("'exclusiveMinimum' constraint only valid if a 'minimum' " throwRuntimeError("'exclusiveMinimum' constraint only valid if a 'minimum' "
"constraint is also present"); "constraint is also present");
} }
@ -815,7 +820,7 @@ private:
if ((itr = object.find("multipleOf")) != object.end()) { if ((itr = object.find("multipleOf")) != object.end()) {
if (m_version == kDraft3) { if (m_version == kDraft3) {
throw std::runtime_error("'multipleOf' constraint not available in draft 3"); throwRuntimeError("'multipleOf' constraint not available in draft 3");
} else if (itr->second.maybeInteger()) { } else if (itr->second.maybeInteger()) {
rootSchema.addConstraintToSubschema( rootSchema.addConstraintToSubschema(
makeMultipleOfIntConstraint(itr->second), makeMultipleOfIntConstraint(itr->second),
@ -825,7 +830,7 @@ private:
makeMultipleOfDoubleConstraint(itr->second), makeMultipleOfDoubleConstraint(itr->second),
&subschema); &subschema);
} else { } else {
throw std::runtime_error("Expected an numeric value for 'divisibleBy' constraint."); throwRuntimeError("Expected an numeric value for 'divisibleBy' constraint.");
} }
} }
@ -878,7 +883,7 @@ private:
nodePath, fetchDoc, docCache, schemaCache), nodePath, fetchDoc, docCache, schemaCache),
&subschema); &subschema);
} else { } else {
throw std::runtime_error("Not supported"); throwRuntimeError("Not supported");
} }
} }
@ -891,7 +896,7 @@ private:
rootSchema.addConstraintToSubschema(*constraint, parentSubschema); rootSchema.addConstraintToSubschema(*constraint, parentSubschema);
} }
} else { } else {
throw std::runtime_error("'required' constraint not valid here"); throwRuntimeError("'required' constraint not valid here");
} }
} else { } else {
rootSchema.addConstraintToSubschema(makeRequiredConstraint(itr->second), &subschema); rootSchema.addConstraintToSubschema(makeRequiredConstraint(itr->second), &subschema);
@ -902,7 +907,7 @@ private:
if (itr->second.maybeString()) { if (itr->second.maybeString()) {
rootSchema.setSubschemaTitle(&subschema, itr->second.asString()); rootSchema.setSubschemaTitle(&subschema, itr->second.asString());
} else { } else {
throw std::runtime_error("'title' attribute should have a string value"); throwRuntimeError("'title' attribute should have a string value");
} }
} }
@ -923,14 +928,18 @@ private:
for (const auto & constraintBuilder : constraintBuilders) { for (const auto & constraintBuilder : constraintBuilders) {
if ((itr = object.find(constraintBuilder.first)) != object.end()) { if ((itr = object.find(constraintBuilder.first)) != object.end()) {
constraints::Constraint *constraint = nullptr; constraints::Constraint *constraint = nullptr;
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
constraint = constraintBuilder.second->make(itr->second); constraint = constraintBuilder.second->make(itr->second);
rootSchema.addConstraintToSubschema(*constraint, &subschema); rootSchema.addConstraintToSubschema(*constraint, &subschema);
delete constraint; delete constraint;
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
delete constraint; delete constraint;
throw; throw;
} }
#endif
} }
} }
} }
@ -992,14 +1001,14 @@ private:
if (documentUri && internal::uri::isUriAbsolute(*documentUri)) { if (documentUri && internal::uri::isUriAbsolute(*documentUri)) {
// Resolve reference against remote document // Resolve reference against remote document
if (!fetchDoc) { if (!fetchDoc) {
throw std::runtime_error("Fetching of remote JSON References not enabled."); throwRuntimeError("Fetching of remote JSON References not enabled.");
} }
const typename DocumentCache<AdapterType>::DocumentType *newDoc = fetchDoc(*documentUri); const typename DocumentCache<AdapterType>::DocumentType *newDoc = fetchDoc(*documentUri);
// Can't proceed without the remote document // Can't proceed without the remote document
if (!newDoc) { if (!newDoc) {
throw std::runtime_error("Failed to fetch referenced schema document: " + *documentUri); throwRuntimeError("Failed to fetch referenced schema document: " + *documentUri);
} }
// Add to document cache // Add to document cache
@ -1056,7 +1065,7 @@ private:
SchemaCache &schemaCache) SchemaCache &schemaCache)
{ {
if (!node.maybeArray()) { if (!node.maybeArray()) {
throw std::runtime_error("Expected array value for 'allOf' constraint."); throwRuntimeError("Expected array value for 'allOf' constraint.");
} }
constraints::AllOfConstraint constraint; constraints::AllOfConstraint constraint;
@ -1071,7 +1080,7 @@ private:
constraint.addSubschema(subschema); constraint.addSubschema(subschema);
index++; index++;
} else { } else {
throw std::runtime_error("Expected element to be a valid schema in 'allOf' constraint."); throwRuntimeError("Expected element to be a valid schema in 'allOf' constraint.");
} }
} }
@ -1108,7 +1117,7 @@ private:
SchemaCache &schemaCache) SchemaCache &schemaCache)
{ {
if (!node.maybeArray()) { if (!node.maybeArray()) {
throw std::runtime_error("Expected array value for 'anyOf' constraint."); throwRuntimeError("Expected array value for 'anyOf' constraint.");
} }
constraints::AnyOfConstraint constraint; constraints::AnyOfConstraint constraint;
@ -1123,7 +1132,7 @@ private:
constraint.addSubschema(subschema); constraint.addSubschema(subschema);
index++; index++;
} else { } else {
throw std::runtime_error("Expected array element to be a valid schema in 'anyOf' constraint."); throwRuntimeError("Expected array element to be a valid schema in 'anyOf' constraint.");
} }
} }
@ -1262,7 +1271,7 @@ private:
} else { } else {
// All other formats will result in an exception being thrown. // All other formats will result in an exception being thrown.
throw std::runtime_error("Expected valid schema for 'contains' constraint."); throwRuntimeError("Expected valid schema for 'contains' constraint.");
} }
return constraint; return constraint;
@ -1316,7 +1325,7 @@ private:
SchemaCache &schemaCache) SchemaCache &schemaCache)
{ {
if (!node.maybeObject()) { if (!node.maybeObject()) {
throw std::runtime_error("Expected valid subschema for 'dependencies' constraint."); throwRuntimeError("Expected valid subschema for 'dependencies' constraint.");
} }
constraints::DependenciesConstraint dependenciesConstraint; constraints::DependenciesConstraint dependenciesConstraint;
@ -1338,7 +1347,7 @@ private:
if (dependencyName.maybeString()) { if (dependencyName.maybeString()) {
dependentPropertyNames.push_back(dependencyName.getString()); dependentPropertyNames.push_back(dependencyName.getString());
} else { } else {
throw std::runtime_error("Expected string value in dependency list of property '" + throwRuntimeError("Expected string value in dependency list of property '" +
member.first + "' in 'dependencies' constraint."); member.first + "' in 'dependencies' constraint.");
} }
} }
@ -1370,7 +1379,7 @@ private:
// All other types result in an exception being thrown. // All other types result in an exception being thrown.
} else { } else {
throw std::runtime_error("Invalid dependencies definition."); throwRuntimeError("Invalid dependencies definition.");
} }
} }
@ -1468,7 +1477,7 @@ private:
} else { } else {
// Any other format for the additionalItems property will result // Any other format for the additionalItems property will result
// in an exception being thrown. // in an exception being thrown.
throw std::runtime_error("Expected bool or object value for 'additionalItems'"); throwRuntimeError("Expected bool or object value for 'additionalItems'");
} }
} else { } else {
// The default value for the additionalItems property is an empty // The default value for the additionalItems property is an empty
@ -1497,7 +1506,7 @@ private:
index++; index++;
} }
} else { } else {
throw std::runtime_error("Expected array value for non-singular 'items' constraint."); throwRuntimeError("Expected array value for non-singular 'items' constraint.");
} }
} }
@ -1567,7 +1576,7 @@ private:
} else { } else {
// All other formats will result in an exception being thrown. // All other formats will result in an exception being thrown.
throw std::runtime_error("Expected valid schema for singular 'items' constraint."); throwRuntimeError("Expected valid schema for singular 'items' constraint.");
} }
return constraint; return constraint;
@ -1596,7 +1605,7 @@ private:
const AdapterType *exclusiveMaximum) const AdapterType *exclusiveMaximum)
{ {
if (!node.maybeDouble()) { if (!node.maybeDouble()) {
throw std::runtime_error("Expected numeric value for maximum constraint."); throwRuntimeError("Expected numeric value for maximum constraint.");
} }
constraints::MaximumConstraint constraint; constraints::MaximumConstraint constraint;
@ -1604,7 +1613,7 @@ private:
if (exclusiveMaximum) { if (exclusiveMaximum) {
if (!exclusiveMaximum->maybeBool()) { if (!exclusiveMaximum->maybeBool()) {
throw std::runtime_error("Expected boolean value for exclusiveMaximum constraint."); throwRuntimeError("Expected boolean value for exclusiveMaximum constraint.");
} }
constraint.setExclusiveMaximum(exclusiveMaximum->asBool()); constraint.setExclusiveMaximum(exclusiveMaximum->asBool());
@ -1627,7 +1636,7 @@ private:
constraints::MaximumConstraint makeMaximumConstraintExclusive(const AdapterType &node) constraints::MaximumConstraint makeMaximumConstraintExclusive(const AdapterType &node)
{ {
if (!node.maybeDouble()) { if (!node.maybeDouble()) {
throw std::runtime_error("Expected numeric value for maximum constraint."); throwRuntimeError("Expected numeric value for maximum constraint.");
} }
constraints::MaximumConstraint constraint; constraints::MaximumConstraint constraint;
@ -1657,7 +1666,7 @@ private:
} }
} }
throw std::runtime_error("Expected non-negative integer value for 'maxItems' constraint."); throwRuntimeError("Expected non-negative integer value for 'maxItems' constraint.");
} }
/** /**
@ -1681,7 +1690,7 @@ private:
} }
} }
throw std::runtime_error("Expected a non-negative integer value for 'maxLength' constraint."); throwRuntimeError("Expected a non-negative integer value for 'maxLength' constraint.");
} }
/** /**
@ -1707,7 +1716,7 @@ private:
} }
} }
throw std::runtime_error("Expected a non-negative integer for 'maxProperties' constraint."); throwRuntimeError("Expected a non-negative integer for 'maxProperties' constraint.");
} }
/** /**
@ -1728,7 +1737,7 @@ private:
const AdapterType *exclusiveMinimum) const AdapterType *exclusiveMinimum)
{ {
if (!node.maybeDouble()) { if (!node.maybeDouble()) {
throw std::runtime_error("Expected numeric value for minimum constraint."); throwRuntimeError("Expected numeric value for minimum constraint.");
} }
constraints::MinimumConstraint constraint; constraints::MinimumConstraint constraint;
@ -1736,7 +1745,7 @@ private:
if (exclusiveMinimum) { if (exclusiveMinimum) {
if (!exclusiveMinimum->maybeBool()) { if (!exclusiveMinimum->maybeBool()) {
throw std::runtime_error("Expected boolean value for 'exclusiveMinimum' constraint."); throwRuntimeError("Expected boolean value for 'exclusiveMinimum' constraint.");
} }
constraint.setExclusiveMinimum(exclusiveMinimum->asBool()); constraint.setExclusiveMinimum(exclusiveMinimum->asBool());
@ -1759,7 +1768,7 @@ private:
constraints::MinimumConstraint makeMinimumConstraintExclusive(const AdapterType &node) constraints::MinimumConstraint makeMinimumConstraintExclusive(const AdapterType &node)
{ {
if (!node.maybeDouble()) { if (!node.maybeDouble()) {
throw std::runtime_error("Expected numeric value for minimum constraint."); throwRuntimeError("Expected numeric value for minimum constraint.");
} }
constraints::MinimumConstraint constraint; constraints::MinimumConstraint constraint;
@ -1788,7 +1797,7 @@ private:
} }
} }
throw std::runtime_error("Expected a non-negative integer value for 'minItems' constraint."); throwRuntimeError("Expected a non-negative integer value for 'minItems' constraint.");
} }
/** /**
@ -1811,7 +1820,7 @@ private:
} }
} }
throw std::runtime_error("Expected a non-negative integer value for 'minLength' constraint."); throwRuntimeError("Expected a non-negative integer value for 'minLength' constraint.");
} }
@ -1837,7 +1846,7 @@ private:
} }
} }
throw std::runtime_error("Expected a non-negative integer for 'minProperties' constraint."); throwRuntimeError("Expected a non-negative integer for 'minProperties' constraint.");
} }
/** /**
@ -1909,7 +1918,7 @@ private:
return constraint; return constraint;
} }
throw std::runtime_error("Expected object value for 'not' constraint."); throwRuntimeError("Expected object value for 'not' constraint.");
} }
/** /**
@ -2081,7 +2090,7 @@ private:
constraint.setAdditionalPropertiesSubschema(subschema); constraint.setAdditionalPropertiesSubschema(subschema);
} else { } else {
// All other types are invalid // All other types are invalid
throw std::runtime_error("Invalid type for 'additionalProperties' constraint."); throwRuntimeError("Invalid type for 'additionalProperties' constraint.");
} }
} else { } else {
// If an additionalProperties constraint is not provided, then the // If an additionalProperties constraint is not provided, then the
@ -2128,7 +2137,7 @@ private:
const std::string &name) const std::string &name)
{ {
if (!node.maybeBool()) { if (!node.maybeBool()) {
throw std::runtime_error("Expected boolean value for 'required' attribute."); throwRuntimeError("Expected boolean value for 'required' attribute.");
} }
if (node.asBool()) { if (node.asBool()) {
@ -2159,7 +2168,7 @@ private:
for (const AdapterType v : node.getArray()) { for (const AdapterType v : node.getArray()) {
if (!v.maybeString()) { if (!v.maybeString()) {
throw std::runtime_error("Expected required property name to be a string value"); throwRuntimeError("Expected required property name to be a string value");
} }
constraint.addRequiredProperty(v.getString()); constraint.addRequiredProperty(v.getString());
@ -2203,7 +2212,7 @@ private:
if (node.maybeString()) { if (node.maybeString()) {
const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(node.getString()); const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(node.getString());
if (type == TypeConstraint::kAny && m_version == kDraft4) { if (type == TypeConstraint::kAny && m_version == kDraft4) {
throw std::runtime_error("'any' type is not supported in version 4 schemas."); throwRuntimeError("'any' type is not supported in version 4 schemas.");
} }
constraint.addNamedType(type); constraint.addNamedType(type);
@ -2214,7 +2223,7 @@ private:
if (v.maybeString()) { if (v.maybeString()) {
const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(v.getString()); const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(v.getString());
if (type == TypeConstraint::kAny && m_version == kDraft4) { if (type == TypeConstraint::kAny && m_version == kDraft4) {
throw std::runtime_error("'any' type is not supported in version 4 schemas."); throwRuntimeError("'any' type is not supported in version 4 schemas.");
} }
constraint.addNamedType(type); constraint.addNamedType(type);
@ -2226,7 +2235,7 @@ private:
constraint.addSchemaType(subschema); constraint.addSchemaType(subschema);
} else { } else {
throw std::runtime_error("Type name should be a string."); throwRuntimeError("Type name should be a string.");
} }
index++; index++;
@ -2238,7 +2247,7 @@ private:
constraint.addSchemaType(subschema); constraint.addSchemaType(subschema);
} else { } else {
throw std::runtime_error("Type name should be a string."); throwRuntimeError("Type name should be a string.");
} }
return constraint; return constraint;
@ -2266,7 +2275,7 @@ private:
} }
} }
throw std::runtime_error("Expected boolean value for 'uniqueItems' constraint."); throwRuntimeError("Expected boolean value for 'uniqueItems' constraint.");
} }
private: private:

View File

@ -6,6 +6,7 @@
#include <valijson/constraints/constraint.hpp> #include <valijson/constraints/constraint.hpp>
#include <valijson/internal/optional.hpp> #include <valijson/internal/optional.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
@ -69,17 +70,21 @@ public:
*/ */
virtual ~Subschema() virtual ~Subschema()
{ {
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
for (auto constConstraint : m_constraints) { for (auto constConstraint : m_constraints) {
auto *constraint = const_cast<Constraint *>(constConstraint); auto *constraint = const_cast<Constraint *>(constConstraint);
constraint->~Constraint(); constraint->~Constraint();
m_freeFn(constraint); m_freeFn(constraint);
} }
m_constraints.clear(); m_constraints.clear();
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::exception &e) { } catch (const std::exception &e) {
fprintf(stderr, "Caught an exception in Subschema destructor: %s", fprintf(stderr, "Caught an exception in Subschema destructor: %s",
e.what()); e.what());
} }
#endif
} }
/** /**
@ -96,13 +101,17 @@ public:
void addConstraint(const Constraint &constraint) void addConstraint(const Constraint &constraint)
{ {
Constraint *newConstraint = constraint.clone(m_allocFn, m_freeFn); Constraint *newConstraint = constraint.clone(m_allocFn, m_freeFn);
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
m_constraints.push_back(newConstraint); m_constraints.push_back(newConstraint);
#if VALIJSON_USE_EXCEPTIONS
} catch (...) { } catch (...) {
newConstraint->~Constraint(); newConstraint->~Constraint();
m_freeFn(newConstraint); m_freeFn(newConstraint);
throw; throw;
} }
#endif
} }
/** /**
@ -165,7 +174,7 @@ public:
return *m_description; return *m_description;
} }
throw std::runtime_error("Schema does not have a description"); throwRuntimeError("Schema does not have a description");
} }
/** /**
@ -181,7 +190,7 @@ public:
return *m_id; return *m_id;
} }
throw std::runtime_error("Schema does not have an ID"); throwRuntimeError("Schema does not have an ID");
} }
/** /**
@ -197,7 +206,7 @@ public:
return *m_title; return *m_title;
} }
throw std::runtime_error("Schema does not have a title"); throwRuntimeError("Schema does not have a title");
} }
/** /**

View File

@ -4,6 +4,7 @@
#include <json.hpp> #include <json.hpp>
#include <valijson/utils/file_utils.hpp> #include <valijson/utils/file_utils.hpp>
#include <valijson/exceptions.hpp>
namespace valijson { namespace valijson {
namespace utils { namespace utils {
@ -19,6 +20,7 @@ inline bool loadDocument(const std::string &path, nlohmann::json &document)
} }
// Parse schema // Parse schema
#if VALIJSON_USE_EXCEPTION
try { try {
document = nlohmann::json::parse(file); document = nlohmann::json::parse(file);
} catch (std::invalid_argument const& exception) { } catch (std::invalid_argument const& exception) {
@ -26,6 +28,13 @@ inline bool loadDocument(const std::string &path, nlohmann::json &document)
<< "Parse error:" << exception.what() << "\n"; << "Parse error:" << exception.what() << "\n";
return false; return false;
} }
#else
document = nlohmann::json::parse(file, nullptr, false);
if (document.is_discarded()) {
std::cerr << "nlohmann::json failed to parse the document.";
return false;
}
#endif
return true; return true;
} }

View File

@ -4,6 +4,7 @@
#include <sstream> #include <sstream>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
#include <boost/throw_exception.hpp>
#if defined(__clang__) #if defined(__clang__)
# pragma clang diagnostic push # pragma clang diagnostic push
@ -14,20 +15,57 @@
# include <boost/property_tree/json_parser.hpp> # include <boost/property_tree/json_parser.hpp>
#endif #endif
// Source locations were added in boost 1.73.
#include <boost/version.hpp>
#if (BOOST_VERSION > 107300)
#include <boost/assert/source_location.hpp>
#endif
#include <valijson/utils/file_utils.hpp> #include <valijson/utils/file_utils.hpp>
#include <valijson/exceptions.hpp>
#if !VALIJSON_USE_EXCEPTION
namespace boost {
// Boost requires used-defined exception throwers when exceptions are
// disabled.
// NOTE: BOOST_NORETURN attribute was added in 1.71.
#if (BOOST_VERSION >= 107100)
BOOST_NORETURN
#endif
void throw_exception(std::exception const & e ) {
valijson::throwRuntimeError(e.what());
}
// Source location override was added in 1.73.
#if (BOOST_VERSION >= 107300)
BOOST_NORETURN
void throw_exception(std::exception const & e, boost::source_location const & loc ) {
valijson::throwRuntimeError(e.what());
}
#endif
} // namespace boost
#endif
namespace valijson { namespace valijson {
namespace utils { namespace utils {
inline bool loadDocument(const std::string &path, boost::property_tree::ptree &document) inline bool loadDocument(const std::string &path, boost::property_tree::ptree &document)
{ {
#if !defined(BOOST_NO_EXCEPTIONS)
try { try {
#endif
boost::property_tree::read_json(path, document); boost::property_tree::read_json(path, document);
#if !defined(BOOST_NO_EXCEPTIONS)
} catch (std::exception &e) { } catch (std::exception &e) {
std::cerr << "Boost Property Tree JSON parser failed to parse the document:" << std::endl; std::cerr << "Boost Property Tree JSON parser failed to parse the document:" << std::endl;
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
return false; return false;
} }
#endif
return true; return true;
} }

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
#include <assert.h>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <valijson/exceptions.hpp>
/* /*
Basic UTF-8 manipulation routines, adapted from code that was released into Basic UTF-8 manipulation routines, adapted from code that was released into
@ -21,14 +25,14 @@ inline bool isutf(char c) {
} }
/* reads the next utf-8 sequence out of a string, updating an index */ /* reads the next utf-8 sequence out of a string, updating an index */
inline uint32_t u8_nextchar(const char *s, int *i) inline uint64_t u8_nextchar(const char *s, uint64_t *i)
{ {
uint32_t ch = 0; uint64_t ch = 0;
int sz = 0; int sz = 0;
do { do {
ch <<= 6; ch <<= 6;
ch += (unsigned char)s[(*i)++]; ch += static_cast<unsigned char>(s[(*i)++]);
sz++; sz++;
} while (s[*i] && !isutf(s[*i])); } while (s[*i] && !isutf(s[*i]));
ch -= offsetsFromUTF8[sz-1]; ch -= offsetsFromUTF8[sz-1];
@ -39,14 +43,13 @@ inline uint32_t u8_nextchar(const char *s, int *i)
/* number of characters */ /* number of characters */
inline uint64_t u8_strlen(const char *s) inline uint64_t u8_strlen(const char *s)
{ {
static const int maxLength = std::numeric_limits<int>::max(); constexpr auto maxLength = std::numeric_limits<uint64_t>::max();
uint64_t count = 0; uint64_t count = 0;
int i = 0; uint64_t i = 0;
while (s[i] != 0 && u8_nextchar(s, &i) != 0) { while (s[i] != 0 && u8_nextchar(s, &i) != 0) {
if (i == maxLength) { if (i == maxLength) {
throw std::runtime_error( throwRuntimeError(
"String exceeded maximum size of " + "String exceeded maximum size of " +
std::to_string(maxLength) + " bytes."); std::to_string(maxLength) + " bytes.");
} }

View File

@ -22,12 +22,13 @@ TEST_F(TestJson11Adapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow // Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types // it to be cast to other types
valijson::adapters::Json11Adapter adapter(document); valijson::adapters::Json11Adapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() ); ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() ); ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements // Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() ); EXPECT_EQ( numElements, adapter.getArray().size() );
@ -59,12 +60,13 @@ TEST_F(TestJson11Adapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not // Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types // allow it to be cast to other types
valijson::adapters::Json11Adapter adapter(document); valijson::adapters::Json11Adapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() ); ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() ); ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members // Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() ); EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -298,7 +298,12 @@ TEST_F(TestJsonPointer, JsonPointerTestCases)
const RapidJsonAdapter actualAdapter = resolveJsonPointer(valueAdapter, jsonPointer); const RapidJsonAdapter actualAdapter = resolveJsonPointer(valueAdapter, jsonPointer);
EXPECT_TRUE(actualAdapter.equalTo(expectedAdapter, true)) << testCase->description; EXPECT_TRUE(actualAdapter.equalTo(expectedAdapter, true)) << testCase->description;
} else { } else {
// Since the tests with throwing disabled will abort, we can't
// do anything here.
#if VALIJSON_USE_EXCEPTIONS
EXPECT_THROW(resolveJsonPointer(valueAdapter, jsonPointer), std::runtime_error) << testCase->description; EXPECT_THROW(resolveJsonPointer(valueAdapter, jsonPointer), std::runtime_error) << testCase->description;
#endif
} }
} }
} }

View File

@ -21,12 +21,13 @@ TEST_F(TestJsonCppAdapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow // Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types // it to be cast to other types
valijson::adapters::JsonCppAdapter adapter(document); valijson::adapters::JsonCppAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() ); ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() ); ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements // Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() ); EXPECT_EQ( numElements, adapter.getArray().size() );
@ -57,11 +58,13 @@ TEST_F(TestJsonCppAdapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not // Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types // allow it to be cast to other types
valijson::adapters::JsonCppAdapter adapter(document); valijson::adapters::JsonCppAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() ); ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() ); ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members // Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() ); EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -21,11 +21,13 @@ TEST_F(TestNlohmannJsonAdapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow // Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types // it to be cast to other types
valijson::adapters::NlohmannJsonAdapter adapter(document); valijson::adapters::NlohmannJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() ); ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() ); ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements // Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() ); EXPECT_EQ( numElements, adapter.getArray().size() );
@ -56,11 +58,13 @@ TEST_F(TestNlohmannJsonAdapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not // Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types // allow it to be cast to other types
valijson::adapters::NlohmannJsonAdapter adapter(document); valijson::adapters::NlohmannJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() ); ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() ); ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members // Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() ); EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -24,11 +24,13 @@ TEST_F(TestPicoJsonAdapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow // Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types // it to be cast to other types
valijson::adapters::PicoJsonAdapter adapter(document); valijson::adapters::PicoJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() ); ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() ); ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements // Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() ); EXPECT_EQ( numElements, adapter.getArray().size() );
@ -61,11 +63,13 @@ TEST_F(TestPicoJsonAdapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not // Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types // allow it to be cast to other types
valijson::adapters::PicoJsonAdapter adapter(document); valijson::adapters::PicoJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() ); ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() ); ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members // Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() ); EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -23,11 +23,13 @@ TEST_F(TestPropertyTreeAdapter, BasicArrayIteration)
// Ensure that wrapping the document preserves the array and does not allow // Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types // it to be cast to other types
valijson::adapters::PropertyTreeAdapter adapter(document); valijson::adapters::PropertyTreeAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() ); ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() ); ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements // Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() ); EXPECT_EQ( numElements, adapter.getArray().size() );
@ -62,11 +64,13 @@ TEST_F(TestPropertyTreeAdapter, BasicObjectIteration)
// Ensure that wrapping the document preserves the object and does not // Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types // allow it to be cast to other types
valijson::adapters::PropertyTreeAdapter adapter(document); valijson::adapters::PropertyTreeAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() ); ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() ); ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members // Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() ); EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -26,11 +26,13 @@ void testBasicArrayIteration()
// Ensure that wrapping the document preserves the array and does not allow // Ensure that wrapping the document preserves the array and does not allow
// it to be cast to other types // it to be cast to other types
valijson::adapters::RapidJsonAdapter adapter(document); valijson::adapters::RapidJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getArray() ); ASSERT_NO_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getObject() ); ASSERT_ANY_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the array contains the expected number of elements // Ensure that the array contains the expected number of elements
EXPECT_EQ( numElements, adapter.getArray().size() ); EXPECT_EQ( numElements, adapter.getArray().size() );
@ -66,11 +68,13 @@ void testBasicObjectIteration()
// Ensure that wrapping the document preserves the object and does not // Ensure that wrapping the document preserves the object and does not
// allow it to be cast to other types // allow it to be cast to other types
valijson::adapters::RapidJsonAdapter adapter(document); valijson::adapters::RapidJsonAdapter adapter(document);
#if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW( adapter.getObject() ); ASSERT_NO_THROW( adapter.getObject() );
ASSERT_ANY_THROW( adapter.getArray() ); ASSERT_ANY_THROW( adapter.getArray() );
ASSERT_ANY_THROW( adapter.getBool() ); ASSERT_ANY_THROW( adapter.getBool() );
ASSERT_ANY_THROW( adapter.getDouble() ); ASSERT_ANY_THROW( adapter.getDouble() );
ASSERT_ANY_THROW( adapter.getString() ); ASSERT_ANY_THROW( adapter.getString() );
#endif
// Ensure that the object contains the expected number of members // Ensure that the object contains the expected number of members
EXPECT_EQ( numElements, adapter.getObject().size() ); EXPECT_EQ( numElements, adapter.getObject().size() );

View File

@ -36,7 +36,11 @@ TEST_F(TestValidationErrors, AllOfConstraintFailure)
// Parse schema document // Parse schema document
Schema schema; Schema schema;
SchemaParser schemaParser; SchemaParser schemaParser;
ASSERT_NO_THROW( schemaParser.populateSchema(schemaAdapter, schema) ); #if VALIJSON_USE_EXCEPTIONS
ASSERT_NO_THROW(schemaParser.populateSchema(schemaAdapter, schema));
#else
schemaParser.populateSchema(schemaAdapter, schema);
#endif
// Load test document // Load test document
rapidjson::Document testDocument; rapidjson::Document testDocument;

View File

@ -16,6 +16,7 @@
#include <valijson/schema_parser.hpp> #include <valijson/schema_parser.hpp>
#include <valijson/validation_results.hpp> #include <valijson/validation_results.hpp>
#include <valijson/validator.hpp> #include <valijson/validator.hpp>
#include <valijson/exceptions.hpp>
#ifdef VALIJSON_BUILD_POCO_ADAPTER #ifdef VALIJSON_BUILD_POCO_ADAPTER
#include <valijson/adapters/poco_json_adapter.hpp> #include <valijson/adapters/poco_json_adapter.hpp>
@ -52,7 +53,7 @@ std::string getRelativePath(const std::string &uri)
return "../doc/schema/draft-04.json"; return "../doc/schema/draft-04.json";
} }
throw std::runtime_error("Attempt fetchDoc of " + uri); valijson::throwRuntimeError("Attempt fetchDoc of " + uri);
} }
template<typename AdapterType> template<typename AdapterType>
@ -66,7 +67,7 @@ const typename AdapterTraits<AdapterType>::DocumentType * fetchDocument(
if (!valijson::utils::loadDocument(relativePath, *document)) { if (!valijson::utils::loadDocument(relativePath, *document)) {
delete document; delete document;
throw std::runtime_error("Failed fetchDoc of " + uri); valijson::throwRuntimeError("Failed fetchDoc of " + uri);
} }
return document; return document;
@ -89,8 +90,9 @@ protected:
std::string currentTestCase; std::string currentTestCase;
std::string currentTest; std::string currentTest;
#if VALIJSON_USE_EXCEPTIONS
try { try {
#endif
// Load test document // Load test document
typename AdapterTraits<AdapterType>::DocumentType document; typename AdapterTraits<AdapterType>::DocumentType document;
ASSERT_TRUE( valijson::utils::loadDocument(testFile, document) ); ASSERT_TRUE( valijson::utils::loadDocument(testFile, document) );
@ -152,13 +154,14 @@ protected:
<< AdapterTraits<AdapterType>::adapterName() << "'"; << AdapterTraits<AdapterType>::adapterName() << "'";
} }
} }
#if VALIJSON_USE_EXCEPTIONS
} catch (const std::exception &e) { } catch (const std::exception &e) {
FAIL() << "Exception thrown with message '" << e.what() FAIL() << "Exception thrown with message '" << e.what()
<< "' in '" << currentTest << "' of test case '" << "' in '" << currentTest << "' of test case '"
<< currentTestCase << "' with adapter '" << currentTestCase << "' with adapter '"
<< AdapterTraits<AdapterType>::adapterName() << "'"; << AdapterTraits<AdapterType>::adapterName() << "'";
} }
#endif
} }
void processTestFile(const std::string &testFile, void processTestFile(const std::string &testFile,