From c07ce50908403b5b15075e6f18871e1ff4c25a37 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 11 Jul 2018 19:28:13 +1000 Subject: [PATCH] json/schema: modularise the validator objects --- CMakeLists.txt | 15 ++++ json/schema.cpp | 28 ++++++++ json/schema.hpp | 15 ++++ json/schema/base.cpp | 39 +++++++++++ json/schema/base.hpp | 51 ++++++++++++++ json/schema/combine.cpp | 78 +++++++++++++++++++++ json/schema/combine.hpp | 52 ++++++++++++++ json/schema/except.hpp | 64 +++++++++++++++++ json/schema/fwd.hpp | 30 ++++++++ json/schema/inequality.cpp | 75 ++++++++++++++++++++ json/schema/inequality.hpp | 49 +++++++++++++ json/schema/introspection.hpp | 35 ++++++++++ json/schema/length.cpp | 83 ++++++++++++++++++++++ json/schema/length.hpp | 42 +++++++++++ json/schema/properties.cpp | 81 +++++++++++++++++++++ json/schema/properties.hpp | 40 +++++++++++ json/schema/type.cpp | 128 ++++++++++++++++++++++++++++++++++ json/schema/type.hpp | 47 +++++++++++++ tools/json-schema.cpp | 15 ++-- 19 files changed, 963 insertions(+), 4 deletions(-) create mode 100644 json/schema/base.cpp create mode 100644 json/schema/base.hpp create mode 100644 json/schema/combine.cpp create mode 100644 json/schema/combine.hpp create mode 100644 json/schema/except.hpp create mode 100644 json/schema/fwd.hpp create mode 100644 json/schema/inequality.cpp create mode 100644 json/schema/inequality.hpp create mode 100644 json/schema/introspection.hpp create mode 100644 json/schema/length.cpp create mode 100644 json/schema/length.hpp create mode 100644 json/schema/properties.cpp create mode 100644 json/schema/properties.hpp create mode 100644 json/schema/type.cpp create mode 100644 json/schema/type.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ec2685f3..6566c5af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,6 +298,21 @@ list ( json/flat.hpp json/schema.cpp json/schema.hpp + json/schema/fwd.hpp + json/schema/base.cpp + json/schema/base.hpp + json/schema/combine.cpp + json/schema/combine.hpp + json/schema/except.hpp + json/schema/introspection.hpp + json/schema/length.cpp + json/schema/length.hpp + json/schema/inequality.cpp + json/schema/inequality.hpp + json/schema/properties.cpp + json/schema/properties.hpp + json/schema/type.cpp + json/schema/type.hpp json/tree.cpp json/tree.hpp json2/fwd.hpp diff --git a/json/schema.cpp b/json/schema.cpp index 47e9eb8d..af4038be 100644 --- a/json/schema.cpp +++ b/json/schema.cpp @@ -538,3 +538,31 @@ json::schema::validate (json::tree::node &data, auto schema_object = json::tree::parse (util::view(schema_data).cast ()); validate (data, schema_object->as_object ()); } + + +/////////////////////////////////////////////////////////////////////////////// +#include "schema/except.hpp" +#include "schema/base.hpp" + +#include "../io.hpp" +#include "../view.hpp" + +#include + +json::schema::validator::validator(std::experimental::filesystem::path const &path): + validator (*json::tree::parse (path)) +{ ; } + + +json::schema::validator::validator (json::tree::node const &definition): + m_base (definition) +{ ; } + + +bool +json::schema::validator::validate (json::tree::node &data) const +{ + std::vector res; + m_base.validate (std::back_inserter(res), data); + return res.empty (); +} diff --git a/json/schema.hpp b/json/schema.hpp index 4398bf1d..b0d524ac 100644 --- a/json/schema.hpp +++ b/json/schema.hpp @@ -18,12 +18,27 @@ #define __UTIL_JSON_SCHEMA_HPP #include "fwd.hpp" +#include "schema/combine.hpp" #include /////////////////////////////////////////////////////////////////////////////// namespace json::schema { + class validator { + public: + validator (json::tree::node const &definition); + validator (std::experimental::filesystem::path const&); + + bool validate (json::tree::node &data) const; + + private: + std::string m_version; + + util::json::schema::constraint::combine m_base; + }; + + // Validate the json tree using the provide schema object or path. // // Note that the data object being validated may be altered in the process diff --git a/json/schema/base.cpp b/json/schema/base.cpp new file mode 100644 index 00000000..41377731 --- /dev/null +++ b/json/schema/base.cpp @@ -0,0 +1,39 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2018 Danny Robson + */ + +#include "base.hpp" + +#include "type.hpp" +#include "length.hpp" +#include "inequality.hpp" +#include "properties.hpp" + +using util::json::schema::constraint::base; + + +/////////////////////////////////////////////////////////////////////////////// +std::unique_ptr +base::instantiate (std::string const &name, ::json::tree::node const &def) +{ + if (name == "type") return std::make_unique (def); + if (name == "minLength") return std::make_unique (def); + if (name == "maxLength") return std::make_unique (def); + if (name == "minimum") return std::make_unique (def); + if (name == "maximum") return std::make_unique (def); + if (name == "properties") return std::make_unique (def); + + throw unknown_constraint (name); +} diff --git a/json/schema/base.hpp b/json/schema/base.hpp new file mode 100644 index 00000000..44bffecd --- /dev/null +++ b/json/schema/base.hpp @@ -0,0 +1,51 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2018 Danny Robson + */ + +#pragma once + +#include "except.hpp" + +#include +#include +#include + + +namespace util::json::schema::constraint { + struct failure { + constraint::base const &rule; + ::json::tree::node const ⌖ + }; + + + class base { + public: + using output_container = std::vector; + using output_iterator = std::back_insert_iterator; + + virtual ~base () = default; + virtual output_iterator validate (output_iterator res, ::json::tree::node &) const noexcept = 0; + virtual std::ostream& describe (std::ostream&) const = 0; + + static std::unique_ptr instantiate (std::string const &name, ::json::tree::node const&); + }; + + + inline std::ostream& + operator<< (std::ostream &os, base const &obj) + { + return obj.describe (os); + } +} diff --git a/json/schema/combine.cpp b/json/schema/combine.cpp new file mode 100644 index 00000000..436af908 --- /dev/null +++ b/json/schema/combine.cpp @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2018 Danny Robson + */ + +#include "combine.hpp" + +#include "../tree.hpp" + +#include "../../iterator.hpp" + +using util::json::schema::constraint::combine; + + +/////////////////////////////////////////////////////////////////////////////// +combine::combine (::json::tree::node const &def) +{ + for (auto const &[key,val]: def.as_object ()) { + if (key == "$schema") { + m_version = val->as_string (); + continue; + } + + if (key == "default") { + m_default = val->clone (); + continue; + } + + m_constraints.push_back (instantiate (key, *val)); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +combine::output_iterator +combine::validate (output_iterator res, ::json::tree::node &data) const noexcept +{ + for (auto const &i: m_constraints) + res = i->validate (res, data); + return res; +} + + +/////////////////////////////////////////////////////////////////////////////// +std::ostream& +combine::describe (std::ostream &os) const +{ + return os << "{ combine: [ "; + for (auto const &i: m_constraints) + os << *i << ", "; + return os << " ] }"; +} + + +/////////////////////////////////////////////////////////////////////////////// +bool +combine::has_default (void) const +{ + return !!m_default; +} + +//----------------------------------------------------------------------------- +std::unique_ptr<::json::tree::node> +combine::default_value (void) const +{ + return m_default->clone (); +} diff --git a/json/schema/combine.hpp b/json/schema/combine.hpp new file mode 100644 index 00000000..5e6b714c --- /dev/null +++ b/json/schema/combine.hpp @@ -0,0 +1,52 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2018 Danny Robson + */ + +#pragma once + +#include "base.hpp" +#include "../tree.hpp" + +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +namespace util::json::schema::constraint { + class combine final : public base { + public: + combine (::json::tree::node const &def); + + combine (combine const&) = delete; + combine& operator= (combine const&) = delete; + + combine (combine &&) = default; + combine& operator= (combine &&) = default; + + virtual ~combine () = default; + + output_iterator validate (output_iterator res, ::json::tree::node &) const noexcept override; + std::ostream& describe (std::ostream&) const override; + + bool has_default (void) const; + std::unique_ptr<::json::tree::node> default_value (void) const; + + private: + std::string m_version; + std::unique_ptr<::json::tree::node> m_default; + + std::vector> m_constraints; + }; +} \ No newline at end of file diff --git a/json/schema/except.hpp b/json/schema/except.hpp new file mode 100644 index 00000000..8fa23c45 --- /dev/null +++ b/json/schema/except.hpp @@ -0,0 +1,64 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2018 Danny Robson + */ + +#pragma once + +#include "fwd.hpp" +#include "introspection.hpp" +#include "../fwd.hpp" + +#include + + +/////////////////////////////////////////////////////////////////////////////// +namespace util::json::schema { + class error : public std::exception { }; + + + template + class constraint_error : public error { + public: + virtual ~constraint_error () = default; + constraint_error (::json::tree::node const &_def): + def (_def) + { ; } + + char const* what (void) const noexcept override + { + return util::type_name_v; + } + + ::json::tree::node const &def; + }; + + + class unknown_constraint : public error { + public: + unknown_constraint (std::string const &name): + m_name (name) + { ; } + + virtual ~unknown_constraint () = default; + + char const* what (void) const noexcept override + { + return m_name.c_str (); + } + + private: + std::string m_name; + }; +} diff --git a/json/schema/fwd.hpp b/json/schema/fwd.hpp new file mode 100644 index 00000000..6922f953 --- /dev/null +++ b/json/schema/fwd.hpp @@ -0,0 +1,30 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2018 Danny Robson + */ + +#pragma once + + +namespace util::json::schema::constraint { + struct failure; + + class base; + + class type; + class combine; + template class length; + template