From 3a362b5bb8afa4d1a278254b29e7b2cfecf319b2 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 7 Aug 2018 10:14:59 -0400 Subject: [PATCH 01/20] Add valijson as git submodule (header-only library) --- .gitmodules | 3 +++ CMakeLists.txt | 3 ++- extern/valijson | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) create mode 160000 extern/valijson diff --git a/.gitmodules b/.gitmodules index 7dc790c..437467b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "tests/googletest"] path = tests/googletest url = https://github.com/google/googletest +[submodule "extern/valijson"] + path = extern/valijson + url = https://github.com/tristanpenman/valijson diff --git a/CMakeLists.txt b/CMakeLists.txt index 50923a5..9ea9ff9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,8 @@ find_package(zlib) find_package(bzip2) set( INCLUDE_DIR include ) -include_directories( ${INCLUDE_DIR} ${YAML_INCLUDE_DIR} ) +set( VALIJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern/valijson/include" ) +include_directories( ${INCLUDE_DIR} ${YAML_INCLUDE_DIR} ${VALIJSON_INCLUDE_DIR} ) set(asdf_c_flags ${CMAKE_C_FLAGS}) set(asdf_cxx_flags ${CMAKE_CXX_FLAGS}) diff --git a/extern/valijson b/extern/valijson new file mode 160000 index 0000000..c2f22fd --- /dev/null +++ b/extern/valijson @@ -0,0 +1 @@ +Subproject commit c2f22fddf599d04dc33fcd7ed257c698a05345d9 From b76e5daef3a9fb18ab29e87bc479a567727bb041 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 7 Aug 2018 12:47:28 -0400 Subject: [PATCH 02/20] Checkpoint: commit first steps towards schema validation --- src/validation.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 src/validation.cpp diff --git a/src/validation.cpp b/src/validation.cpp new file mode 100644 index 0000000..2d12c9f --- /dev/null +++ b/src/validation.cpp @@ -0,0 +1,233 @@ +#include +#include +#include + +#include + +#include +#include +#include + + +using valijson::adapters::Adapter; +using valijson::adapters::BasicAdapter; +using valijson::adapters::FrozenValue; + + +class YamlCppArray +{ + +}; + + +class YamlCppObjectMember +{ + +}; + + +class YamlCppObject +{ + +}; + + +class YamlCppFrozenNode: public FrozenValue +{ + public: + /** + * @brief Make a copy of a YAML Node + * + * @param source the YAML node to be copied + */ + explicit YamlCppFrozenNode(const YAML::Node &source) : node(source) { } + + virtual FrozenValue * clone() const + { + return new YamlCppFrozenNode(node); + } + + virtual bool equalTo(const Adapter &other, bool strict) const; + +private: + + /// Stored YAML node + YAML::Node node; + +}; + + +/** + * @brief Light weight wrapper for a YAML node. + * + * This class is passed as an argument to the BasicAdapter template class, and + * is used to provide access to a YAML node. This class is responsible for the + * mechanics of actually reading a YAML node, whereas the BasicAdapter class is + * responsible for the semantics of type comparisons and conversions. + * + * The functions that need to be provided by this class are defined implicitly + * by the implementation of the BasicAdapter template class. + * + * @see BasicAdapter + */ +class YamlCppNode +{ + public: + + YamlCppNode() : node(emptyObject()) { } + YamlCppNode(const YAML::Node &node) : node(node) { } + + /** + * @brief Create a new YamlCppFrozenNode instance that contains the + * value referenced by this YamlCppNode instance. + * + * @returns pointer to a new YamlCppFrozenNode instance, belonging to + * the caller. + */ + FrozenValue * freeze() const + { + return new YamlCppFrozenNode(node); + } + + /* + * YAML does not assign strict types to node values. This means that + * many of the "is*" and "get*" methods below will also return false. + */ + static bool hasStrictTypes() + { + return false; + } + + bool getObjectSize(size_t &result) const + { + if (node.IsNull()) + { + return false; + } + + result = node.size(); + return true; + } + + bool getArraySize(size_t &result) const + { + return getObjectSize(result); + } + + bool getBool(bool &) const + { + return false; + } + + bool getDouble(double &) const + { + return false; + } + + bool getInteger(int64_t &) const + { + return false; + } + + bool getString(std::string &result) const + { + result = node.as(); + return true; + } + + /** + * @brief Optionally return a YamlCppArray instance. + * + * If the referenced YAML node is an array, this function will return a + * std::optional containing a YamlCppArray instance referencing the + * array. + * + * Otherwise it will return an empty optional. + */ + opt::optional getArrayOptional() const + { + if (isArray()) { + return opt::make_optional(YamlCppArray(node)); + } + + return opt::optional(); + } + + bool isArray() const + { + return node.IsSequence() && !node.IsNull(); + } + + bool isInteger() const + { + return false; + } + + bool isDouble() const + { + return false; + } + + bool isNumber() const + { + return false; + } + + bool isBool() const + { + return false; + } + + bool isString() const + { + return false; + } + + bool isObject() const + { + return false; + } + + bool isNull() const + { + return node.IsNull(); + } + + private: + + static const YAML::Node& emptyObject() + { + static const YAML::Node object; + return object; + } + + const YAML::Node &node; +}; + + +class YamlCppAdapter: + public BasicAdapter +{ + public: + + YamlCppAdapter() : BasicAdapter() { } + YamlCppAdapter(const YAML::Node &node) : BasicAdapter(node) { } + +}; + + +int main(int argc, char **argv) +{ + if (argc != 2) + { + fprintf(stderr, "USAGE: %s \n", argv[0]); + return 1; + } + + YAML::Node schema = YAML::LoadFile(argv[1]); + YamlCppAdapter schemaAdapter(schema); +} From a04be75d4c97e822720a8fe7c470b1deee1c5214 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 7 Aug 2018 13:41:31 -0400 Subject: [PATCH 03/20] Implement YamlCppArray class --- src/validation.cpp | 165 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 2d12c9f..7260277 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1,3 +1,7 @@ +/** + * The bulk of this file represents an implementation of a custom JSON Schema + * adapter that allows YAML schemas and files to be used for validation. + */ #include #include #include @@ -12,11 +16,83 @@ using valijson::adapters::Adapter; using valijson::adapters::BasicAdapter; using valijson::adapters::FrozenValue; +using valijson::adapters::DerefProxy; + + +class YamlCppArrayValueIterator; +/** + * @brief Light weight wrapper for a YamlCpp array node. + * + * This class is light weight wrapper for a YamlCpp array. It provides a + * minimum set of container functions and typedefs that allow it to be used as + * an iterable container. + * + * An instance of this class contains a single reference to the underlying + * YamlCpp node, assumed to be an array, so there is very little overhead + * associated with copy construction and passing by node. + */ class YamlCppArray { +public: + typedef YamlCppArrayValueIterator const_iterator; + typedef YamlCppArrayValueIterator iterator; + + /// Construct a YamlCppArray referencing an empty array. + YamlCppArray() : node(emptyArray()) { } + + /** + * @brief Construct a YamlCppArray referencing a specific YAML node. + * + * @param node reference to a YAML node + * + * Note that this constructor will throw an exception if the node is not + * an array. + */ + YamlCppArray(const YAML::Node &node) : node(node) + { + if (!node.IsSequence()) { + throw std::runtime_error("Node is not an array."); + } + } + + /** + * @brief Return an iterator for the first element of the array. + * + * The iterator return by this function is effectively the iterator + * returned by the underlying YamlCpp implementation. + */ + YamlCppArrayValueIterator begin() const; + + /** + * @brief Return an iterator for one-past the last element of the array. + * + * The iterator return by this function is effectively the iterator + * returned by the underlying YamlCpp implementation. + */ + YamlCppArrayValueIterator end() const; + + /// Return the number of elements in the array. + size_t size() const + { + return node.size(); + } +private: + /** + * @brief Return a reference to a YamlCpp node that is an empty array. + * + * Note that the value returned by this function is a singleton. + */ + static const YAML::Node & emptyArray() + { + static const YAML::Node array(YAML::NodeType::Sequence); + return array; + } + + /// Reference to the contained array + const YAML::Node &node; }; @@ -220,6 +296,95 @@ class YamlCppAdapter: }; +/** + * @brief Class for iterating over values held in a YAML array. + * + * This class provides a YAML array iterator that dereferences as an instance + * of YamlCppAdapter representing a value stored in the array. + * + * @see YamlCppArray + */ +class YamlCppArrayValueIterator: + public std::iterator< + std::forward_iterator_tag, // forward iterator tag + YamlCppAdapter> // value type +{ + +public: + + /** + * @brief Construct a new YamlCppArrayValueIterator using an existing + * YamlCpp iterator. + * + * @param itr YamlCpp iterator to store + */ + YamlCppArrayValueIterator(const YAML::Node::const_iterator &itr) + : itr(itr) { } + + /// Returns a YamlCppAdapter that contains the value of the current element. + YamlCppAdapter operator*() const + { + return YamlCppAdapter(*itr); + } + + DerefProxy operator->() const + { + return DerefProxy(**this); + } + + /** + * @brief Compare this iterator against another iterator. + * + * Note that this directly compares the iterators, not the underlying + * values, and assumes that two identical iterators will point to the same + * underlying object. + * + * @param rhs iterator to compare against + * + * @returns true if the iterators are equal, false otherwise. + */ + bool operator==(const YamlCppArrayValueIterator &rhs) const + { + return itr == rhs.itr; + } + + bool operator!=(const YamlCppArrayValueIterator &rhs) const + { + return !(itr == rhs.itr); + } + + YamlCppArrayValueIterator& operator++() + { + itr++; + + return *this; + } + + YamlCppArrayValueIterator operator++(int) + { + YamlCppArrayValueIterator iterator_pre(itr); + ++(*this); + return iterator_pre; + } + + void advance(std::ptrdiff_t n) + { + if (n < 0) { + throw std::runtime_error( + "Attempt to use negative increment on forward iterator"); + } + + while (n-- > 0) { + itr++; + } + } + +private: + + YAML::Node::const_iterator itr; +}; + + int main(int argc, char **argv) { if (argc != 2) From 6ebccbd82a33db57e10104254c2f383d8d5f5890 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 7 Aug 2018 15:43:32 -0400 Subject: [PATCH 04/20] Validation compiles but more work required --- src/validation.cpp | 235 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 229 insertions(+), 6 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 7260277..3a882cf 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -19,7 +19,11 @@ using valijson::adapters::FrozenValue; using valijson::adapters::DerefProxy; +class YamlCppAdapter; class YamlCppArrayValueIterator; +class YamlCppObjectMemberIterator; + +typedef std::pair YamlCppObjectMember; /** @@ -96,15 +100,85 @@ class YamlCppArray }; -class YamlCppObjectMember +/** + * @brief Light weight wrapper for a YAML object. + * + * This class is light weight wrapper for a YAML object. It provides a + * minimum set of container functions and typedefs that allow it to be used as + * an iterable container. + * + * An instance of this class contains a single reference to the underlying + * YAML object, assumed to be an object, so there is very little overhead + * associated with copy construction and passing by value. + */ +class YamlCppObject { +public: -}; + typedef YamlCppObjectMemberIterator const_iterator; + typedef YamlCppObjectMemberIterator iterator; + /// Construct a YamlCppObject referencing an empty object singleton. + YamlCppObject() : node(emptyObject()) { } -class YamlCppObject -{ + /** + * @brief Construct a YamlCppObject referencing a specific YAML node. + * + * @param node reference to a YAML node + * + * Note that this constructor will throw an exception if the node is not + * an object. + */ + YamlCppObject(const YAML::Node &node) : node(node) + { + if (!node.IsMap()) { + throw std::runtime_error("Value is not an object."); + } + } + /** + * @brief Return an iterator for this first object member + * + * The iterator return by this function is effectively a wrapper around + * the iterator value returned by the underlying YamlCpp implementation. + */ + YamlCppObjectMemberIterator begin() const; + + /** + * @brief Return an iterator for an invalid object member that indicates + * the end of the collection. + * + * The iterator return by this function is effectively a wrapper around + * the iterator value returned by the underlying YamlCpp implementation. + */ + YamlCppObjectMemberIterator end() const; + + /** + * @brief Return an iterator for a member/property with the given name + * + * @param propertyName Property name + * + * @returns a valid iterator if found, or an invalid iterator if not found + */ + YamlCppObjectMemberIterator find(const std::string &propertyName) const; + + /// Return the number of members in the object + size_t size() const + { + return node.size(); + } + +private: + + /// Return a reference to an empty YamlCpp object + static const YAML::Node & emptyObject() + { + static const YAML::Node object(YAML::NodeType::Map); + return object; + } + + /// Reference to the contained object + const YAML::Node &node; }; @@ -229,6 +303,24 @@ class YamlCppNode return opt::optional(); } + /** + * @brief Optionally return a YamlCppObject instance. + * + * If the referenced YAML node is an object, this function will return + * a std::optional containing a YamlCppObject instance referencing the + * object. + * + * Otherwise it will return an empty optional. + */ + opt::optional getObjectOptional() const + { + if (isObject()) { + return opt::make_optional(YamlCppObject(node)); + } + + return opt::optional(); + } + bool isArray() const { return node.IsSequence() && !node.IsNull(); @@ -261,7 +353,7 @@ class YamlCppNode bool isObject() const { - return false; + return isNull() && node.IsMap(); } bool isNull() const @@ -385,14 +477,145 @@ class YamlCppArrayValueIterator: }; +/** + * @brief Class for iterating over the members belonging to a YAML object. + * + * This class provides a YAML object iterator that dereferences as an instance + * of YamlCppObjectMember representing one of the members of the object. It has + * been implemented using the boost iterator_facade template. + * + * @see YamlCppObject + * @see YamlCppObjectMember + */ +class YamlCppObjectMemberIterator: + public std::iterator< + std::forward_iterator_tag, // forward iterator + YamlCppObjectMember> // value type +{ +public: + + /** + * @brief Construct an iterator from a YamlCpp iterator. + * + * @param itr YamlCpp iterator to store + */ + YamlCppObjectMemberIterator(const YAML::const_iterator &itr) : itr(itr) { } + + /** + * @brief Returns a YamlCppObjectMember that contains the key and value + * belonging to the object member identified by the iterator. + */ + YamlCppObjectMember operator*() const + { + return YamlCppObjectMember("", *itr); + } + + DerefProxy operator->() const + { + return DerefProxy(**this); + } + + /** + * @brief Compare this iterator with another iterator. + * + * Note that this directly compares the iterators, not the underlying + * values, and assumes that two identical iterators will point to the same + * underlying object. + * + * @param rhs Iterator to compare with + * + * @returns true if the underlying iterators are equal, false otherwise + */ + bool operator==(const YamlCppObjectMemberIterator &rhs) const + { + return itr == rhs.itr; + } + + bool operator!=(const YamlCppObjectMemberIterator &rhs) const + { + return !(itr == rhs.itr); + } + + const YamlCppObjectMemberIterator& operator++() + { + itr++; + + return *this; + } + + YamlCppObjectMemberIterator operator++(int) + { + YamlCppObjectMemberIterator iterator_pre(itr); + ++(*this); + return iterator_pre; + } + +private: + + /// Iternal copy of the original YamlCpp iterator + YAML::const_iterator itr; +}; + + +inline bool YamlCppFrozenNode::equalTo(const Adapter &other, bool strict) const +{ + return YamlCppAdapter(node).equalTo(other, strict); +} + + +inline YamlCppArrayValueIterator YamlCppArray::begin() const +{ + return node.begin(); +} + + +inline YamlCppArrayValueIterator YamlCppArray::end() const +{ + return node.end(); +} + + +inline YamlCppObjectMemberIterator YamlCppObject::begin() const +{ + return node.begin(); +} + + +inline YamlCppObjectMemberIterator YamlCppObject::end() const +{ + return node.end(); +} + + +inline YamlCppObjectMemberIterator YamlCppObject::find( + const std::string &propertyName) const +{ +#if 0 + for (auto itr = node.begin(); itr != node.end(); ++itr) { + if (itr->first == propertyName) { + return itr; + } + } +#endif + + return node.end(); +} + int main(int argc, char **argv) { - if (argc != 2) + if (argc != 3) { fprintf(stderr, "USAGE: %s \n", argv[0]); return 1; } YAML::Node schema = YAML::LoadFile(argv[1]); + std::cout << schema << std::endl; + std::cout << schema.Scalar() << std::endl; + for (auto itr = schema.begin(); itr != schema.end(); ++itr) + { + std::cout << itr->first << std::endl; + } + YamlCppAdapter schemaAdapter(schema); } From c2e0f9e1d350be8fd50555738c8c2ba7382df6cf Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 7 Aug 2018 15:43:55 -0400 Subject: [PATCH 05/20] Temporary change to CMakeLists.txt to support testing of validation --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea9ff9..1e8953c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,9 @@ set_target_properties(asdf-cpp PROPERTIES COMPILE_FLAGS "${asdf_c_flags} ${asdf_cxx_flags}" ) +add_executable( validator src/validation.cpp ) +target_link_libraries( validator yaml-cpp ) + if (${ZLIB_FOUND}) target_compile_definitions(asdf-cpp PRIVATE HAS_ZLIB=1) target_include_directories(asdf-cpp PRIVATE ${ZLIB_INCLUDE_DIRS}) From a10db17c0051973ff826234aa5f2d4c13ba9f2d1 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 10:55:16 -0400 Subject: [PATCH 06/20] Fix YAML object iterator --- src/validation.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 3a882cf..f2a148e 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -590,13 +590,11 @@ inline YamlCppObjectMemberIterator YamlCppObject::end() const inline YamlCppObjectMemberIterator YamlCppObject::find( const std::string &propertyName) const { -#if 0 for (auto itr = node.begin(); itr != node.end(); ++itr) { - if (itr->first == propertyName) { + if (itr->first.as() == propertyName) { return itr; } } -#endif return node.end(); } @@ -610,12 +608,5 @@ int main(int argc, char **argv) } YAML::Node schema = YAML::LoadFile(argv[1]); - std::cout << schema << std::endl; - std::cout << schema.Scalar() << std::endl; - for (auto itr = schema.begin(); itr != schema.end(); ++itr) - { - std::cout << itr->first << std::endl; - } - YamlCppAdapter schemaAdapter(schema); } From aede35af1f2491b2f4ae8720c4e477cdea30fcdf Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 11:45:45 -0400 Subject: [PATCH 07/20] Fix test for isObject --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index f2a148e..5a350a4 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -353,7 +353,7 @@ class YamlCppNode bool isObject() const { - return isNull() && node.IsMap(); + return !isNull() && node.IsMap(); } bool isNull() const From c1ea65eed2eab1a809f2edee38a8c5e4d3139436 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 11:46:46 -0400 Subject: [PATCH 08/20] Fix dereference operator for object member --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 5a350a4..318b17d 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -507,7 +507,7 @@ class YamlCppObjectMemberIterator: */ YamlCppObjectMember operator*() const { - return YamlCppObjectMember("", *itr); + return YamlCppObjectMember(itr->first.as(), itr->second); } DerefProxy operator->() const From 6ebeac07296a5292b2ce2f6bf3838e1c21c76218 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 11:47:01 -0400 Subject: [PATCH 09/20] Add AdapterTraits specialization for Yaml schema --- src/validation.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 318b17d..ec903b4 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -599,6 +599,20 @@ inline YamlCppObjectMemberIterator YamlCppObject::find( return node.end(); } + +/// Specialization of the AdapterTraits template struct for YamlCppAdapter. +template<> +struct valijson::adapters::AdapterTraits +{ + typedef YAML::Node DocumentType; + + static std::string adapterName() + { + return "YamlCppAdapter"; + } +}; + + int main(int argc, char **argv) { if (argc != 3) From 8af7733df2839e43046d8aa5d887a1931bee181e Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 13:28:56 -0400 Subject: [PATCH 10/20] Add code to populate schema --- src/validation.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index ec903b4..55c3720 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -621,6 +621,10 @@ int main(int argc, char **argv) return 1; } - YAML::Node schema = YAML::LoadFile(argv[1]); - YamlCppAdapter schemaAdapter(schema); + YAML::Node yaml_schema = YAML::LoadFile(argv[1]); + + valijson::Schema schema; + valijson::SchemaParser parser; + YamlCppAdapter schemaAdapter(yaml_schema); + parser.populateSchema(schemaAdapter, schema); } From 58bf4b27f791a63ebcdeeb78fca6c8a233aa7ce6 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 13:29:36 -0400 Subject: [PATCH 11/20] First apparently incorrect dereference in iterator --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 55c3720..b553149 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -507,7 +507,7 @@ class YamlCppObjectMemberIterator: */ YamlCppObjectMember operator*() const { - return YamlCppObjectMember(itr->first.as(), itr->second); + return YamlCppObjectMember(itr->first.as(), *itr); } DerefProxy operator->() const From acb0cc3b5bd21196bde43817eca667731f9029d9 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Wed, 8 Aug 2018 13:42:01 -0400 Subject: [PATCH 12/20] Make sure to treat valijson headers as system headers --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e8953c..0d95fdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,8 @@ find_package(bzip2) set( INCLUDE_DIR include ) set( VALIJSON_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/extern/valijson/include" ) -include_directories( ${INCLUDE_DIR} ${YAML_INCLUDE_DIR} ${VALIJSON_INCLUDE_DIR} ) +include_directories( ${INCLUDE_DIR} ${YAML_INCLUDE_DIR} ) +include_directories( SYSTEM ${VALIJSON_INCLUDE_DIR} ) set(asdf_c_flags ${CMAKE_C_FLAGS}) set(asdf_cxx_flags ${CMAKE_CXX_FLAGS}) From e84839470d563bfb56c8c514dcd34a8511d8e7cf Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Thu, 9 Aug 2018 12:25:31 -0400 Subject: [PATCH 13/20] Fix dereference of YamlCppObjectMemberIterator --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index b553149..55c3720 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -507,7 +507,7 @@ class YamlCppObjectMemberIterator: */ YamlCppObjectMember operator*() const { - return YamlCppObjectMember(itr->first.as(), *itr); + return YamlCppObjectMember(itr->first.as(), itr->second); } DerefProxy operator->() const From 7dc841a6206710df78adac436fea6eff4e861e5d Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Thu, 9 Aug 2018 12:56:55 -0400 Subject: [PATCH 14/20] Fix semantics of isObject method of YamlCppNode --- src/validation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 55c3720..17cd270 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -353,7 +353,7 @@ class YamlCppNode bool isObject() const { - return !isNull() && node.IsMap(); + return node.IsMap() && !node.IsNull(); } bool isNull() const From 4e5291f5aab6cd52242353675e67d8c131261d8d Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Thu, 9 Aug 2018 13:52:57 -0400 Subject: [PATCH 15/20] Override maybeString method from BasicAdapter --- src/validation.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/validation.cpp b/src/validation.cpp index 17cd270..0db79a1 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -383,8 +383,17 @@ class YamlCppAdapter: public: YamlCppAdapter() : BasicAdapter() { } - YamlCppAdapter(const YAML::Node &node) : BasicAdapter(node) { } + YamlCppAdapter(const YAML::Node &node) : BasicAdapter(node), node(node) + { } + + bool maybeString() const + { + return !(node.isObject() || node.isArray()) ; + } + + private: + const YamlCppNode node; }; From fa755a8cda0408c8876c9fcae9e835571e54d9ce Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Thu, 9 Aug 2018 14:03:22 -0400 Subject: [PATCH 16/20] Intermediate progress: override asString for YamlCppAdapter --- src/validation.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/validation.cpp b/src/validation.cpp index 0db79a1..7295fbe 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -392,6 +392,28 @@ class YamlCppAdapter: return !(node.isObject() || node.isArray()) ; } + std::string asString() const + { + std::string result; + if (asString(result)) + { + return result; + } + + throw std::runtime_error("YAML value cannot be cast to string"); + } + + bool asString(std::string &result) const + { + if (maybeString()) + { + node.getString(result); + return true; + } + + return false; + } + private: const YamlCppNode node; }; From b38e5cbf79201ed0efe8699bff9804f2cf3f6db2 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Thu, 23 Aug 2018 16:05:35 -0400 Subject: [PATCH 17/20] Fix segfault that occurred during schema processing --- src/validation.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 7295fbe..f2b9958 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -225,7 +225,7 @@ class YamlCppNode public: YamlCppNode() : node(emptyObject()) { } - YamlCppNode(const YAML::Node &node) : node(node) { } + YamlCppNode(const YAML::Node node) : node(node) { } /** * @brief Create a new YamlCppFrozenNode instance that contains the @@ -369,7 +369,7 @@ class YamlCppNode return object; } - const YAML::Node &node; + const YAML::Node node; }; @@ -382,8 +382,8 @@ class YamlCppAdapter: { public: - YamlCppAdapter() : BasicAdapter() { } - YamlCppAdapter(const YAML::Node &node) : BasicAdapter(node), node(node) + YamlCppAdapter() : BasicAdapter(), node() { } + YamlCppAdapter(const YAML::Node node) : BasicAdapter(node), node(node) { } From 9e5e17181ad9657cc7b59adbd852a6c146a19b67 Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Fri, 24 Aug 2018 14:35:04 -0400 Subject: [PATCH 18/20] Initial steps towards schema reference resolution --- extern/valijson | 2 +- src/validation.cpp | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/extern/valijson b/extern/valijson index c2f22fd..67efb56 160000 --- a/extern/valijson +++ b/extern/valijson @@ -1 +1 @@ -Subproject commit c2f22fddf599d04dc33fcd7ed257c698a05345d9 +Subproject commit 67efb56b2c5b3a264ca8c744f79ad1883963588e diff --git a/src/validation.cpp b/src/validation.cpp index f2b9958..941b846 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -644,6 +644,35 @@ struct valijson::adapters::AdapterTraits }; +class AsdfSchemaParser : public valijson::SchemaParser +{ + /* Overridden from implementation in Schema parser */ + opt::optional findAbsoluteDocumentUri( + const opt::optional resolutionScope, + const opt::optional documentUri) + { + namespace internal = valijson::internal; + + std::string base = "/Users/ddavella/asdf/asdf-standard/schemas/stsci.edu/asdf/core/"; + return base + documentUri.value() + ".yaml"; + } +}; + + +const YAML::Node * fetchYamlDoc(const std::string &uri) +{ + YAML::Node temp = YAML::LoadFile(uri); + YAML::Node *node = new YAML::Node(temp); + return node; +} + + +void freeYamlDoc(const YAML::Node *node) +{ + delete node; +} + + int main(int argc, char **argv) { if (argc != 3) @@ -655,7 +684,7 @@ int main(int argc, char **argv) YAML::Node yaml_schema = YAML::LoadFile(argv[1]); valijson::Schema schema; - valijson::SchemaParser parser; + AsdfSchemaParser parser; YamlCppAdapter schemaAdapter(yaml_schema); - parser.populateSchema(schemaAdapter, schema); + parser.populateSchema(schemaAdapter, schema, fetchYamlDoc, freeYamlDoc); } From 24f1ff08d50b8cefb1e158cce28708bb1d382d5c Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 28 Aug 2018 15:19:36 -0400 Subject: [PATCH 19/20] More intermediate progress towards schema validation --- extern/valijson | 2 +- src/validation.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/extern/valijson b/extern/valijson index 67efb56..137ab38 160000 --- a/extern/valijson +++ b/extern/valijson @@ -1 +1 @@ -Subproject commit 67efb56b2c5b3a264ca8c744f79ad1883963588e +Subproject commit 137ab38d58812ae6c6def55ffbc0211058618a1b diff --git a/src/validation.cpp b/src/validation.cpp index 941b846..23dc629 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -392,6 +392,23 @@ class YamlCppAdapter: return !(node.isObject() || node.isArray()) ; } + virtual bool maybeBool() const + { + if (maybeString()) + { + std::string stringValue; + if (node.getString(stringValue)) + { + if (stringValue.compare("true") == 0 || stringValue.compare("false") == 0) + { + return true; + } + } + } + + return false; + } + std::string asString() const { std::string result; @@ -414,6 +431,32 @@ class YamlCppAdapter: return false; } + bool asBool(bool &result) const + { + std::string s; + if (node.getString(s)) { + if (s.compare("true") == 0) { + result = true; + return true; + } else if (s.compare("false") == 0) { + result = false; + return true; + } + } + + return false; + } + + bool asBool() const + { + bool result; + if (asBool(result)) { + return result; + } + + throw std::runtime_error("JSON value cannot be cast to a boolean."); + } + private: const YamlCppNode node; }; From 74e6949ad467d97eb199b0ce72ca91ca46ea96cf Mon Sep 17 00:00:00 2001 From: Daniel D'Avella Date: Tue, 4 Sep 2018 14:38:32 -0400 Subject: [PATCH 20/20] Push some adapter workarounds up into valijson --- extern/valijson | 2 +- src/validation.cpp | 43 ------------------------------------------- 2 files changed, 1 insertion(+), 44 deletions(-) diff --git a/extern/valijson b/extern/valijson index 137ab38..23f83b7 160000 --- a/extern/valijson +++ b/extern/valijson @@ -1 +1 @@ -Subproject commit 137ab38d58812ae6c6def55ffbc0211058618a1b +Subproject commit 23f83b756bf3a588657e41f04d82ae5279b8ceb4 diff --git a/src/validation.cpp b/src/validation.cpp index 23dc629..941b846 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -392,23 +392,6 @@ class YamlCppAdapter: return !(node.isObject() || node.isArray()) ; } - virtual bool maybeBool() const - { - if (maybeString()) - { - std::string stringValue; - if (node.getString(stringValue)) - { - if (stringValue.compare("true") == 0 || stringValue.compare("false") == 0) - { - return true; - } - } - } - - return false; - } - std::string asString() const { std::string result; @@ -431,32 +414,6 @@ class YamlCppAdapter: return false; } - bool asBool(bool &result) const - { - std::string s; - if (node.getString(s)) { - if (s.compare("true") == 0) { - result = true; - return true; - } else if (s.compare("false") == 0) { - result = false; - return true; - } - } - - return false; - } - - bool asBool() const - { - bool result; - if (asBool(result)) { - return result; - } - - throw std::runtime_error("JSON value cannot be cast to a boolean."); - } - private: const YamlCppNode node; };