From 592e6db083997f2b943d0629b627f44b53286dbd Mon Sep 17 00:00:00 2001 From: Tristan Penman Date: Tue, 22 Dec 2015 10:26:51 +1100 Subject: [PATCH] Move functionality from Schema class to a new Subschema class (superclass for Schema), and remove dead code --- CMakeLists.txt | 1 - include/valijson/schema.hpp | 254 +---------------------- include/valijson/subschema.hpp | 254 +++++++++++++++++++++++ tests/test_uri_resolution.cpp | 19 -- xcode/valijson.xcodeproj/project.pbxproj | 6 +- 5 files changed, 264 insertions(+), 270 deletions(-) create mode 100644 include/valijson/subschema.hpp delete mode 100644 tests/test_uri_resolution.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d39d24f..4faa89d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,6 @@ add_executable(test_suite tests/test_property_tree_adapter.cpp tests/test_rapidjson_adapter.cpp tests/test_picojson_adapter.cpp - tests/test_uri_resolution.cpp tests/test_validation_errors.cpp tests/test_validator.cpp ) diff --git a/include/valijson/schema.hpp b/include/valijson/schema.hpp index 50d476e..c396d56 100644 --- a/include/valijson/schema.hpp +++ b/include/valijson/schema.hpp @@ -1,59 +1,26 @@ #ifndef __VALIJSON_SCHEMA_HPP #define __VALIJSON_SCHEMA_HPP -#include -#include -#include -#include - -#include +#include namespace valijson { /** - * @brief Class that holds a list of Constraints that together form a schema. + * Represents the root of a JSON Schema * - * This class maintains an internal list of Constraint objects that define a - * schema. It provides useful functionality such as the ability to easily make - * independent copies of a schema. - * - * Schemas can be modified after construction by adding more constraints, or - * by setting a schema title. + * The root is distinct from other sub-schemas because it is the canonical + * starting point for validation of a document against a given a JSON Schema. */ -class Schema +class Schema: public Subschema { public: - - /// Typedef the Constraint class into the local namespace for convenience - typedef constraints::Constraint Constraint; - - /// Typedef for a function that can be applied to each of the Constraint - /// instances owned by a Schema. - typedef boost::function ApplyFunction; - /** - * @brief Construct a new Schema object with no constraints, using the - * default scope. - * - * The constructed Schema object will have no constraints. + * @brief Construct a new Schema instance with no constraints */ Schema() { } /** - * @brief Construct a new Schema object with no constraints, and inherit - * the scope of another Schema. - * - * The functions getScope(), getCanonicalURI() and getInheritedURI() use - * the scope provided by this constructor, unless the URI for this schema - * specifies its own scope. - * - * @param parentScope Scope to inherit. - */ - Schema(const std::string &parentScope) - : parentScope(parentScope) {} - - /** - * @brief Construct a new Schema based an existing Schema object. + * @brief Construct a new Schema based an existing Schema instance * * The constructed Schema object will contain a copy of each constraint * defined in the referenced Schema. @@ -61,213 +28,8 @@ public: * @param schema schema to copy constraints from */ Schema(const Schema &schema) - : constraints(schema.constraints), - parentScope(schema.parentScope), - title(schema.title) { } + : Subschema(schema) { } - /** - * @brief Add a constraint to the schema. - * - * A copy of the referenced Constraint object will be added to the Schema. - * - * @param constraint Reference to the constraint to copy. - */ - void addConstraint(const Constraint &constraint) - { - constraints.push_back(constraint.clone()); - } - - /** - * @brief Add a constraint to the schema. - * - * The schema will take ownership of the provided Constraint. - * - * @param constraint Pointer to the constraint to take ownership of. - */ - void addConstraint(Constraint *constraint) - { - constraints.push_back(constraint); - } - - /** - * @brief Invoke a function on each constraint in the schema. - * - * This function will apply the callback function to each constraint in - * the schema, even if one of the invokations returns false. If a single - * invokation returns false, this function will return false. - * - * @returns true if all invokations of the callback function are - * successful, false otherwise. - */ - bool apply(ApplyFunction &applyFunction) const - { - bool allTrue = true; - BOOST_FOREACH( const Constraint &constraint, constraints ) { - allTrue = allTrue && applyFunction(constraint); - } - - return allTrue; - } - - /** - * @brief Invoke a function on each constraint in the schema. - * - * This is a stricter version of the apply() function that will return - * immediately if any of the invokations return false. - * - * @returns true if all invokations of the callback function are - * successful, false otherwise. - */ - bool applyStrict(ApplyFunction &applyFunction) const - { - BOOST_FOREACH( const Constraint &constraint, constraints ) { - if (!applyFunction(constraint)) { - return false; - } - } - - return true; - } - - /** - * @brief Get the description for this schema - * - * @throw std::runtime_error if the description has not been set - * - * @return schema description - */ - std::string getDescription() const - { - if (description) { - return *description; - } - - throw std::runtime_error("Schema does not have a description"); - } - - std::string getId() const - { - if (id) { - return *id; - } - - throw std::runtime_error("id has not been set"); - } - - std::string getScope() const - { - return std::string(); - } - - std::string getUri() const - { - return std::string(); - } - - /** - * @brief Get the title for this schema. - * - * If the title has not been set, this function will throw an exception. - * - * @throw std::runtime_error - * - * @return schema title string - */ - std::string getTitle() const - { - if (title) { - return *title; - } - - throw std::runtime_error("Schema does not have a title."); - } - - /** - * @brief Returns a boolean value that indicates whether the description - * has been set or not - * - * @return boolean value - */ - bool hasDescription() const - { - return description != boost::none; - } - - /** - * @brief Returns a boolean value that indicates whether the id has been - * set or not. - * - * @return boolean value - */ - bool hasId() const - { - return id != boost::none; - } - - /** - * @brief Returns a boolean value that indicates whether the schema title - * has been set or not. - * - * @return boolean value - */ - bool hasTitle() const - { - return title != boost::none; - } - - std::string resolveUri(const std::string &relative) const - { - return relative; - } - - /** - * @brief Set the description for this schema - * - * The description will not be used for validation, but may be used as part - * of the user interface used to interact with a schema. - * - * @param description new description - */ - void setDescription(const std::string &description) - { - this->description = description; - } - - void setId(const std::string &id) - { - this->id = id; - } - - /** - * @brief Set the title for this schema. - * - * The title is not used for validation, but can be used as part of the - * validation error descriptions that are produced by the Validator and - * ValidationVisitor classes. - * - * @param title new title - */ - void setTitle(const std::string &title) - { - this->title = title; - } - -private: - - /// List of pointers to constraints that apply to this schema. - boost::ptr_vector constraints; - - /// Schema description (optional) - boost::optional description; - - /// Id to apply when resolving the schema URI. - boost::optional id; - - /// Scope inherited from a parent schema, or an empty string by default - boost::optional parentScope; - - /// Title string associated with the schema (optional). - boost::optional title; }; } // namespace valijson diff --git a/include/valijson/subschema.hpp b/include/valijson/subschema.hpp new file mode 100644 index 0000000..269ee1c --- /dev/null +++ b/include/valijson/subschema.hpp @@ -0,0 +1,254 @@ +#ifndef __VALIJSON_SUBSCHEMA_HPP +#define __VALIJSON_SUBSCHEMA_HPP + +#include +#include +#include +#include + +#include + +namespace valijson { + +/** + * Represents a sub-schema within a JSON Schema + * + * While all JSON Schemas have at least one sub-schema, the root, some will + * have additional sub-schemas that are defined as part of constraints that are + * included in the schema. For example, a 'oneOf' constraint maintains a set of + * references to one or more nested sub-schemas. As per the definition of a + * oneOf constraint, a document is valid within that constraint if it validates + * against one of the nested sub-schemas. + */ +class Subschema +{ +public: + /// Typedef the Constraint class into the local namespace for convenience + typedef constraints::Constraint Constraint; + + /// Typedef for a function that can be applied to each of the Constraint + /// instances owned by a Schema. + typedef boost::function ApplyFunction; + + /** + * @brief Construct a new Subschema object with no constraints + */ + Subschema() { } + + /** + * @brief Copy an existing Subschema + * + * The constructed Subschema instance will contain a copy of each constraint + * defined in the referenced Subschemas. Constraints will be copied only + * as deep as references to other Subschemas - e.g. copies of constraints + * that refer to sub-schemas, will continue to refer to the same Subschema + * instances. + * + * @param subschema Subschema instance to copy constraints from + */ + Subschema(const Subschema &subschema) + : constraints(subschema.constraints), + title(subschema.title) { } + + /** + * @brief Add a constraint to this sub-schema + * + * The constraint will be copied before being added to the list of + * constraints for this Subschema. Note that constraints will be copied + * only as deep as references to other Subschemas - e.g. copies of + * constraints that refer to sub-schemas, will continue to refer to the + * same Subschema instances. + * + * @param constraint Reference to the constraint to copy + */ + void addConstraint(const Constraint &constraint) + { + constraints.push_back(constraint.clone()); + } + + /** + * @brief Add a constraint to this sub-schema + * + * This Subschema instance will take ownership of Constraint that is + * pointed to, and will free it when it is no longer needed. + * + * @param constraint Pointer to the Constraint to take ownership of + */ + void addConstraint(Constraint *constraint) + { + constraints.push_back(constraint); + } + + /** + * @brief Invoke a function on each child Constraint + * + * This function will apply the callback function to each constraint in + * the Subschema, even if one of the invokations returns \c false. However, + * if one or more invokations of the callback function return \c false, + * this function will also return \c false. + * + * @returns \c true if all invokations of the callback function are + * successful, \c false otherwise + */ + bool apply(ApplyFunction &applyFunction) const + { + bool allTrue = true; + BOOST_FOREACH( const Constraint &constraint, constraints ) { + allTrue = allTrue && applyFunction(constraint); + } + + return allTrue; + } + + /** + * @brief Invoke a function on each child Constraint + * + * This is a stricter version of the apply() function that will return + * immediately if any of the invokations of the callback function return + * \c false. + * + * @returns \c true if all invokations of the callback function are + * successful, \c false otherwise + */ + bool applyStrict(ApplyFunction &applyFunction) const + { + BOOST_FOREACH( const Constraint &constraint, constraints ) { + if (!applyFunction(constraint)) { + return false; + } + } + + return true; + } + + /** + * @brief Get the description associated with this sub-schema + * + * @throws std::runtime_error if a description has not been set + * + * @returns string containing sub-schema description + */ + std::string getDescription() const + { + if (description) { + return *description; + } + + throw std::runtime_error("Schema does not have a description"); + } + + /** + * @brief Get the ID associated with this sub-schema + * + * @throws std::runtime_error if an ID has not been set + * + * @returns string containing sub-schema ID + */ + std::string getId() const + { + if (id) { + return *id; + } + + throw std::runtime_error("Schema does not have an ID"); + } + + /** + * @brief Get the title associated with this sub-schema + * + * @throws std::runtime_error if a title has not been set + * + * @returns string containing sub-schema title + */ + std::string getTitle() const + { + if (title) { + return *title; + } + + throw std::runtime_error("Schema does not have a title"); + } + + /** + * @brief Check whether this sub-schema has a description + * + * @return boolean value + */ + bool hasDescription() const + { + return description != boost::none; + } + + /** + * @brief Check whether this sub-schema has an ID + * + * @return boolean value + */ + bool hasId() const + { + return id != boost::none; + } + + /** + * @brief Check whether this sub-schema has a title + * + * @return boolean value + */ + bool hasTitle() const + { + return title != boost::none; + } + + /** + * @brief Set the description for this sub-schema + * + * The description will not be used for validation, but may be used as part + * of the user interface for interacting with schemas and sub-schemas. As + * an example, it may be used as part of the validation error descriptions + * that are produced by the Validator and ValidationVisitor classes. + * + * @param description new description + */ + void setDescription(const std::string &description) + { + this->description = description; + } + + void setId(const std::string &id) + { + this->id = id; + } + + /** + * @brief Set the title for this sub-schema + * + * The title will not be used for validation, but may be used as part + * of the user interface for interacting with schemas and sub-schema. As an + * example, it may be used as part of the validation error descriptions + * that are produced by the Validator and ValidationVisitor classes. + * + * @param title new title + */ + void setTitle(const std::string &title) + { + this->title = title; + } + +private: + + /// List of pointers to constraints that apply to this schema. + boost::ptr_vector constraints; + + /// Schema description (optional) + boost::optional description; + + /// Id to apply when resolving the schema URI + boost::optional id; + + /// Title string associated with the schema (optional) + boost::optional title; +}; + +} // namespace valijson + +#endif diff --git a/tests/test_uri_resolution.cpp b/tests/test_uri_resolution.cpp deleted file mode 100644 index 5a890b2..0000000 --- a/tests/test_uri_resolution.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#include - -using valijson::Schema; - -class TestUriResolution : public ::testing::Test -{ - -}; - -TEST_F(TestUriResolution, TestDefaultScopeAndUri) -{ - Schema schema; - EXPECT_FALSE( schema.hasId() ); - EXPECT_ANY_THROW( schema.getId() ); - EXPECT_EQ( "", schema.getUri() ); - EXPECT_EQ( "", schema.getScope() ); -} \ No newline at end of file diff --git a/xcode/valijson.xcodeproj/project.pbxproj b/xcode/valijson.xcodeproj/project.pbxproj index f24f25d..40cf507 100644 --- a/xcode/valijson.xcodeproj/project.pbxproj +++ b/xcode/valijson.xcodeproj/project.pbxproj @@ -16,7 +16,6 @@ 6A725F4817F6404100D6B2FF /* test_property_tree_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FEC417E92B100028E147 /* test_property_tree_adapter.cpp */; }; 6A725F4917F6404100D6B2FF /* test_rapidjson_adapter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AC18D3917CC874100FE0EC9 /* test_rapidjson_adapter.cpp */; }; 6A725F4A17F6404100D6B2FF /* test_validator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AC18D3517CC86E000FE0EC9 /* test_validator.cpp */; }; - 6A725F4D17F8964B00D6B2FF /* test_uri_resolution.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A725F4B17F8956A00D6B2FF /* test_uri_resolution.cpp */; }; 6A9E1856194DC44B003F1C4C /* test_fetch_document_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AA8A5DA17F8BDCA002728A0 /* test_fetch_document_callback.cpp */; }; 6AB8FE8717E6A56F0028E147 /* external_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6AB8FE8617E6A56F0028E147 /* external_schema.cpp */; }; 6AB8FE8D17E6A57E0028E147 /* libboost_regex-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A477F8417D6BCBB0013571C /* libboost_regex-mt.dylib */; }; @@ -40,6 +39,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 6A309D2D1C28C1FD00EF761C /* subschema.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = subschema.hpp; sourceTree = ""; }; 6A34698C1BD109A900C97DA2 /* json_reference.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = json_reference.hpp; path = internal/json_reference.hpp; sourceTree = ""; }; 6A477F8417D6BCBB0013571C /* libboost_regex-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_regex-mt.dylib"; path = "/usr/local/lib/libboost_regex-mt.dylib"; sourceTree = ""; }; 6A506D121AF884E100C2C818 /* draft-03.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "draft-03.json"; sourceTree = ""; }; @@ -70,7 +70,6 @@ 6A725F4017F61A4400D6B2FF /* object_empty.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = object_empty.json; sourceTree = ""; }; 6A725F4217F61AC200D6B2FF /* allof_integers_and_numbers.schema.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = allof_integers_and_numbers.schema.json; sourceTree = ""; }; 6A725F4317F61B5100D6B2FF /* test_validation_errors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_validation_errors.cpp; sourceTree = ""; }; - 6A725F4B17F8956A00D6B2FF /* test_uri_resolution.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = test_uri_resolution.cpp; sourceTree = ""; }; 6A725F6617F89CD500D6B2FF /* abi_prefix.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = abi_prefix.hpp; sourceTree = ""; }; 6A725F6717F89CD500D6B2FF /* abi_suffix.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = abi_suffix.hpp; sourceTree = ""; }; 6A725F6817F89CD500D6B2FF /* config.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = config.hpp; sourceTree = ""; }; @@ -699,7 +698,6 @@ 6AB8FE9217E6BE770028E147 /* test_jsoncpp_adapter.cpp */, 6AB8FEC417E92B100028E147 /* test_property_tree_adapter.cpp */, 6AC18D3917CC874100FE0EC9 /* test_rapidjson_adapter.cpp */, - 6A725F4B17F8956A00D6B2FF /* test_uri_resolution.cpp */, 6A725F4317F61B5100D6B2FF /* test_validation_errors.cpp */, 6AC18D3517CC86E000FE0EC9 /* test_validator.cpp */, ); @@ -761,6 +759,7 @@ 6A869A2F17CD8A81006864FA /* utils */, 6AC78BE917C5FC6A00674114 /* schema.hpp */, 6AC78BEA17C5FC6A00674114 /* schema_parser.hpp */, + 6A309D2D1C28C1FD00EF761C /* subschema.hpp */, 6AC78BEC17C5FC6A00674114 /* validation_results.hpp */, 6AC18C1517C861D600FE0EC9 /* validation_visitor.hpp */, 6AC78BEE17C5FC6A00674114 /* validator.hpp */, @@ -1002,7 +1001,6 @@ 6A506D201AF88E5D00C2C818 /* test_json_pointer.cpp in Sources */, 6A725F4917F6404100D6B2FF /* test_rapidjson_adapter.cpp in Sources */, 6A725F4A17F6404100D6B2FF /* test_validator.cpp in Sources */, - 6A725F4D17F8964B00D6B2FF /* test_uri_resolution.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };