diff --git a/CMakeLists.txt b/CMakeLists.txt index ff01bed..1bc34cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,7 @@ include(vendor/noa/cmake/noa.cmake) # Options option(ALTERSCHEMA_ENGINE "Build the Alterschema Engine library" ON) +option(ALTERSCHEMA_LINTER "Build the Alterschema Linter library" ON) option(ALTERSCHEMA_TESTS "Build the Alterschema tests" OFF) option(ALTERSCHEMA_DOCS "Build the Alterschema docs" OFF) option(ALTERSCHEMA_INSTALL "Install the Alterschema library" ON) @@ -19,11 +20,15 @@ if(ALTERSCHEMA_INSTALL) # TODO endif() -if(ALTERSCHEMA_ENGINE) +if(ALTERSCHEMA_ENGINE OR ALTERSCHEMA_LINTER) find_package(JSONToolkit REQUIRED) add_subdirectory(src/engine) endif() +if(ALTERSCHEMA_LINTER) + add_subdirectory(src/linter) +endif() + if(ALTERSCHEMA_ADDRESS_SANITIZER) noa_sanitizer(TYPE address) elseif(ALTERSCHEMA_UNDEFINED_SANITIZER) @@ -50,4 +55,8 @@ if(ALTERSCHEMA_TESTS) if(ALTERSCHEMA_ENGINE) add_subdirectory(test/engine) endif() + + if(ALTERSCHEMA_LINTER) + add_subdirectory(test/linter) + endif() endif() diff --git a/Makefile b/Makefile index e1fe130..d776cfe 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ configure: .always -DCMAKE_BUILD_TYPE:STRING=$(PRESET) \ -DCMAKE_COMPILE_WARNING_AS_ERROR:BOOL=ON \ -DALTERSCHEMA_ENGINE:BOOL=ON \ + -DALTERSCHEMA_LINTER:BOOL=ON \ -DALTERSCHEMA_TESTS:BOOL=ON \ -DBUILD_SHARED_LIBS:BOOL=$(SHARED) diff --git a/src/linter/CMakeLists.txt b/src/linter/CMakeLists.txt new file mode 100644 index 0000000..4599a57 --- /dev/null +++ b/src/linter/CMakeLists.txt @@ -0,0 +1,33 @@ +noa_library(NAMESPACE sourcemeta PROJECT alterschema NAME linter + FOLDER "Alterschema/Linter" + SOURCES linter.cc + # Modernize + modernize/enum_to_const.h + + # Antipattern + antipattern/const_with_type.h + antipattern/enum_with_type.h + + # Simplify + simplify/single_type_array.h + + # Redundant + redundant/additional_properties_default.h + redundant/content_media_type_without_encoding.h + redundant/content_schema_default.h + redundant/content_schema_without_media_type.h + redundant/else_without_if.h + redundant/items_array_default.h + redundant/items_schema_default.h + redundant/max_contains_without_contains.h + redundant/min_contains_without_contains.h + redundant/then_without_if.h + redundant/unevaluated_items_default.h + redundant/unevaluated_properties_default.h) + +if(ALTERSCHEMA_INSTALL) + noa_library_install(NAMESPACE sourcemeta PROJECT alterschema NAME linter) +endif() + +target_link_libraries(sourcemeta_alterschema_linter PUBLIC + sourcemeta::alterschema::engine) diff --git a/src/linter/antipattern/const_with_type.h b/src/linter/antipattern/const_with_type.h new file mode 100644 index 0000000..51fe69d --- /dev/null +++ b/src/linter/antipattern/const_with_type.h @@ -0,0 +1,25 @@ +class ConstWithType final : public Rule { +public: + ConstWithType() + : Rule{"const_with_type", + "Setting `type` alongside `const` is considered an anti-pattern, " + "as the constant already implies its respective type"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/validation", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#"}) && + schema.is_object() && schema.defines("type") && + schema.defines("const"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("type"); + } +}; diff --git a/src/linter/antipattern/enum_with_type.h b/src/linter/antipattern/enum_with_type.h new file mode 100644 index 0000000..002969f --- /dev/null +++ b/src/linter/antipattern/enum_with_type.h @@ -0,0 +1,30 @@ +class EnumWithType final : public Rule { +public: + EnumWithType() + : Rule{ + "enum_with_type", + "Setting `type` alongside `enum` is considered an anti-pattern, as " + "the enumeration choices already imply their respective types"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/validation", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#", + "http://json-schema.org/draft-04/schema#", + "http://json-schema.org/draft-03/schema#", + "http://json-schema.org/draft-02/hyper-schema#", + "http://json-schema.org/draft-01/hyper-schema#"}) && + schema.is_object() && schema.defines("type") && + schema.defines("enum"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("type"); + } +}; diff --git a/src/linter/include/sourcemeta/alterschema/linter.h b/src/linter/include/sourcemeta/alterschema/linter.h new file mode 100644 index 0000000..c602711 --- /dev/null +++ b/src/linter/include/sourcemeta/alterschema/linter.h @@ -0,0 +1,32 @@ +#ifndef SOURCEMETA_ALTERSCHEMA_LINTER_H_ +#define SOURCEMETA_ALTERSCHEMA_LINTER_H_ + +#include "linter_export.h" + +#include + +namespace sourcemeta::alterschema { + +/// @ingroup linter +/// The category of a built-in transformation rule +enum class LinterCategory { + /// Rules that make use of newer features within the same dialect + Modernize, + + /// Rules that detect common anti-patterns + AntiPattern, + + /// Rules that simplify the given schema + Simplify, + + /// Rules that remove schema redundancies + Redundant +}; + +/// Add a set of built-in linter rules given a category +SOURCEMETA_ALTERSCHEMA_LINTER_EXPORT +auto add(Bundle &bundle, const LinterCategory category) -> void; + +} // namespace sourcemeta::alterschema + +#endif diff --git a/src/linter/linter.cc b/src/linter/linter.cc new file mode 100644 index 0000000..62a1cfa --- /dev/null +++ b/src/linter/linter.cc @@ -0,0 +1,73 @@ +#include + +#include // assert + +// For built-in rules +#include // std::any_of +#include // std::cbegin, std::cend +namespace sourcemeta::alterschema { +template +auto contains_any(const T &container, const T &values) -> bool { + return std::any_of( + std::cbegin(container), std::cend(container), + [&values](const auto &element) { return values.contains(element); }); +} + +// Modernize +#include "modernize/enum_to_const.h" +// AntiPattern +#include "antipattern/const_with_type.h" +#include "antipattern/enum_with_type.h" +// Simplify +#include "simplify/single_type_array.h" +// Redundant +#include "redundant/additional_properties_default.h" +#include "redundant/content_media_type_without_encoding.h" +#include "redundant/content_schema_default.h" +#include "redundant/content_schema_without_media_type.h" +#include "redundant/else_without_if.h" +#include "redundant/items_array_default.h" +#include "redundant/items_schema_default.h" +#include "redundant/max_contains_without_contains.h" +#include "redundant/min_contains_without_contains.h" +#include "redundant/then_without_if.h" +#include "redundant/unevaluated_items_default.h" +#include "redundant/unevaluated_properties_default.h" +} // namespace sourcemeta::alterschema + +namespace sourcemeta::alterschema { + +auto add(Bundle &bundle, const LinterCategory category) -> void { + switch (category) { + case LinterCategory::Modernize: + bundle.add(); + break; + case LinterCategory::AntiPattern: + bundle.add(); + bundle.add(); + break; + case LinterCategory::Simplify: + bundle.add(); + break; + case LinterCategory::Redundant: + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + bundle.add(); + break; + default: + // We should never get here + assert(false); + break; + } +} + +} // namespace sourcemeta::alterschema diff --git a/src/linter/modernize/enum_to_const.h b/src/linter/modernize/enum_to_const.h new file mode 100644 index 0000000..d7c5694 --- /dev/null +++ b/src/linter/modernize/enum_to_const.h @@ -0,0 +1,26 @@ +class EnumToConst final : public Rule { +public: + EnumToConst() + : Rule("enum_to_const", + "An `enum` of a single value can be expressed as `const`") {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/validation", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#"}) && + schema.is_object() && !schema.defines("const") && + schema.defines("enum") && schema.at("enum").is_array() && + schema.at("enum").size() == 1; + } + + auto transform(Transformer &transformer) const -> void override { + transformer.assign("const", transformer.schema().at("enum").front()); + transformer.erase("enum"); + } +}; diff --git a/src/linter/redundant/additional_properties_default.h b/src/linter/redundant/additional_properties_default.h new file mode 100644 index 0000000..9443eb2 --- /dev/null +++ b/src/linter/redundant/additional_properties_default.h @@ -0,0 +1,32 @@ +class AdditionalPropertiesDefault final : public Rule { +public: + AdditionalPropertiesDefault() + : Rule{"additional_properties_default", + "Setting the `additionalProperties` keyword to the true schema " + "does not add any further constraint"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/applicator", + "https://json-schema.org/draft/2019-09/vocab/applicator", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#", + "http://json-schema.org/draft-04/schema#", + "http://json-schema.org/draft-03/schema#", + "http://json-schema.org/draft-02/hyper-schema#", + "http://json-schema.org/draft-01/hyper-schema#"}) && + schema.is_object() && schema.defines("additionalProperties") && + ((schema.at("additionalProperties").is_boolean() && + schema.at("additionalProperties").to_boolean()) || + (schema.at("additionalProperties").is_object() && + schema.at("additionalProperties").empty())); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("additionalProperties"); + } +}; diff --git a/src/linter/redundant/content_media_type_without_encoding.h b/src/linter/redundant/content_media_type_without_encoding.h new file mode 100644 index 0000000..8a9f47d --- /dev/null +++ b/src/linter/redundant/content_media_type_without_encoding.h @@ -0,0 +1,23 @@ +class ContentMediaTypeWithoutEncoding final : public Rule { +public: + ContentMediaTypeWithoutEncoding() + : Rule{"content_media_type_without_encoding", + "The `contentMediaType` keyword is meaningless " + "without the presence of the `contentEncoding` keyword"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any(vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/content", + "https://json-schema.org/draft/2019-09/vocab/content", + "http://json-schema.org/draft-07/schema#"}) && + schema.is_object() && schema.defines("contentMediaType") && + !schema.defines("contentEncoding"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("contentMediaType"); + } +}; diff --git a/src/linter/redundant/content_schema_default.h b/src/linter/redundant/content_schema_default.h new file mode 100644 index 0000000..1228b23 --- /dev/null +++ b/src/linter/redundant/content_schema_default.h @@ -0,0 +1,26 @@ +class ContentSchemaDefault final : public Rule { +public: + ContentSchemaDefault() + : Rule{"content_schema_default", + "Setting the `contentSchema` keyword to the true schema " + "does not add any further constraint"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/content", + "https://json-schema.org/draft/2019-09/vocab/content"}) && + schema.is_object() && schema.defines("contentSchema") && + ((schema.at("contentSchema").is_boolean() && + schema.at("contentSchema").to_boolean()) || + (schema.at("contentSchema").is_object() && + schema.at("contentSchema").empty())); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("contentSchema"); + } +}; diff --git a/src/linter/redundant/content_schema_without_media_type.h b/src/linter/redundant/content_schema_without_media_type.h new file mode 100644 index 0000000..f39d6d2 --- /dev/null +++ b/src/linter/redundant/content_schema_without_media_type.h @@ -0,0 +1,23 @@ +class ContentSchemaWithoutMediaType final : public Rule { +public: + ContentSchemaWithoutMediaType() + : Rule{"content_schema_without_media_type", + "The `contentSchema` keyword is meaningless without the presence " + "of the `contentMediaType` keyword"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/content", + "https://json-schema.org/draft/2019-09/vocab/content"}) && + schema.is_object() && schema.defines("contentSchema") && + !schema.defines("contentMediaType"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("contentSchema"); + } +}; diff --git a/src/linter/redundant/else_without_if.h b/src/linter/redundant/else_without_if.h new file mode 100644 index 0000000..83f2526 --- /dev/null +++ b/src/linter/redundant/else_without_if.h @@ -0,0 +1,23 @@ +class ElseWithoutIf final : public Rule { +public: + ElseWithoutIf() + : Rule{"else_without_if", "The `else` keyword is meaningless " + "without the presence of the `if` keyword"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/applicator", + "https://json-schema.org/draft/2019-09/vocab/applicator", + "http://json-schema.org/draft-07/schema#"}) && + schema.is_object() && schema.defines("else") && + !schema.defines("if"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("else"); + } +}; diff --git a/src/linter/redundant/items_array_default.h b/src/linter/redundant/items_array_default.h new file mode 100644 index 0000000..b903c51 --- /dev/null +++ b/src/linter/redundant/items_array_default.h @@ -0,0 +1,28 @@ +class ItemsArrayDefault final : public Rule { +public: + ItemsArrayDefault() + : Rule{"items_array_default", + "Setting the `items` keyword to the empty array " + "does not add any further constraint"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2019-09/vocab/applicator", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#", + "http://json-schema.org/draft-04/schema#", + "http://json-schema.org/draft-03/schema#", + "http://json-schema.org/draft-02/hyper-schema#", + "http://json-schema.org/draft-01/hyper-schema#"}) && + schema.is_object() && schema.defines("items") && + schema.at("items").is_array() && schema.at("items").empty(); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("items"); + } +}; diff --git a/src/linter/redundant/items_schema_default.h b/src/linter/redundant/items_schema_default.h new file mode 100644 index 0000000..abc716b --- /dev/null +++ b/src/linter/redundant/items_schema_default.h @@ -0,0 +1,31 @@ +class ItemsSchemaDefault final : public Rule { +public: + ItemsSchemaDefault() + : Rule{"items_schema_default", + "Setting the `items` keyword to the true schema " + "does not add any further constraint"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/applicator", + "https://json-schema.org/draft/2019-09/vocab/applicator", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#", + "http://json-schema.org/draft-04/schema#", + "http://json-schema.org/draft-03/schema#", + "http://json-schema.org/draft-02/hyper-schema#", + "http://json-schema.org/draft-01/hyper-schema#"}) && + schema.is_object() && schema.defines("items") && + ((schema.at("items").is_boolean() && + schema.at("items").to_boolean()) || + (schema.at("items").is_object() && schema.at("items").empty())); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("items"); + } +}; diff --git a/src/linter/redundant/max_contains_without_contains.h b/src/linter/redundant/max_contains_without_contains.h new file mode 100644 index 0000000..3cc9249 --- /dev/null +++ b/src/linter/redundant/max_contains_without_contains.h @@ -0,0 +1,23 @@ +class MaxContainsWithoutContains final : public Rule { +public: + MaxContainsWithoutContains() + : Rule{"max_contains_without_contains", + "The `maxContains` keyword is meaningless " + "without the presence of the `contains` keyword"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/validation"}) && + schema.is_object() && schema.defines("maxContains") && + !schema.defines("contains"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("maxContains"); + } +}; diff --git a/src/linter/redundant/min_contains_without_contains.h b/src/linter/redundant/min_contains_without_contains.h new file mode 100644 index 0000000..73246c6 --- /dev/null +++ b/src/linter/redundant/min_contains_without_contains.h @@ -0,0 +1,23 @@ +class MinContainsWithoutContains final : public Rule { +public: + MinContainsWithoutContains() + : Rule{"min_contains_without_contains", + "The `minContains` keyword is meaningless " + "without the presence of the `contains` keyword"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/validation"}) && + schema.is_object() && schema.defines("minContains") && + !schema.defines("contains"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("minContains"); + } +}; diff --git a/src/linter/redundant/then_without_if.h b/src/linter/redundant/then_without_if.h new file mode 100644 index 0000000..f952f59 --- /dev/null +++ b/src/linter/redundant/then_without_if.h @@ -0,0 +1,23 @@ +class ThenWithoutIf final : public Rule { +public: + ThenWithoutIf() + : Rule{"then_without_if", "The `then` keyword is meaningless " + "without the presence of the `if` keyword"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/applicator", + "https://json-schema.org/draft/2019-09/vocab/applicator", + "http://json-schema.org/draft-07/schema#"}) && + schema.is_object() && schema.defines("then") && + !schema.defines("if"); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("then"); + } +}; diff --git a/src/linter/redundant/unevaluated_items_default.h b/src/linter/redundant/unevaluated_items_default.h new file mode 100644 index 0000000..548ba45 --- /dev/null +++ b/src/linter/redundant/unevaluated_items_default.h @@ -0,0 +1,26 @@ +class UnevaluatedItemsDefault final : public Rule { +public: + UnevaluatedItemsDefault() + : Rule{"unevaluated_items_default", + "Setting the `unevaluatedItems` keyword to the true schema " + "does not add any further constraint"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/unevaluated", + "https://json-schema.org/draft/2019-09/vocab/applicator"}) && + schema.is_object() && schema.defines("unevaluatedItems") && + ((schema.at("unevaluatedItems").is_boolean() && + schema.at("unevaluatedItems").to_boolean()) || + (schema.at("unevaluatedItems").is_object() && + schema.at("unevaluatedItems").empty())); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("unevaluatedItems"); + } +}; diff --git a/src/linter/redundant/unevaluated_properties_default.h b/src/linter/redundant/unevaluated_properties_default.h new file mode 100644 index 0000000..ca5da92 --- /dev/null +++ b/src/linter/redundant/unevaluated_properties_default.h @@ -0,0 +1,26 @@ +class UnevaluatedPropertiesDefault final : public Rule { +public: + UnevaluatedPropertiesDefault() + : Rule{"unevaluated_properties_default", + "Setting the `unevaluatedProperties` keyword to the true schema " + "does not add any further constraint"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/unevaluated", + "https://json-schema.org/draft/2019-09/vocab/applicator"}) && + schema.is_object() && schema.defines("unevaluatedProperties") && + ((schema.at("unevaluatedProperties").is_boolean() && + schema.at("unevaluatedProperties").to_boolean()) || + (schema.at("unevaluatedProperties").is_object() && + schema.at("unevaluatedProperties").empty())); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase("unevaluatedProperties"); + } +}; diff --git a/src/linter/simplify/single_type_array.h b/src/linter/simplify/single_type_array.h new file mode 100644 index 0000000..01a3399 --- /dev/null +++ b/src/linter/simplify/single_type_array.h @@ -0,0 +1,31 @@ +class SingleTypeArray final : public Rule { +public: + SingleTypeArray() + : Rule{"single_type_array", + "Setting `type` to an array of a single type is " + "the same as directly declaring such type"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return contains_any( + vocabularies, + {"https://json-schema.org/draft/2020-12/vocab/validation", + "https://json-schema.org/draft/2019-09/vocab/validation", + "http://json-schema.org/draft-07/schema#", + "http://json-schema.org/draft-06/schema#", + "http://json-schema.org/draft-04/schema#", + "http://json-schema.org/draft-03/schema#", + "http://json-schema.org/draft-02/hyper-schema#", + "http://json-schema.org/draft-01/hyper-schema#", + "http://json-schema.org/draft-00/hyper-schema#"}) && + schema.is_object() && schema.defines("type") && + schema.at("type").is_array() && schema.at("type").size() == 1 && + schema.at("type").front().is_string(); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.replace({"type"}, transformer.schema().at("type").front()); + } +}; diff --git a/test/linter/2019_09_test.cc b/test/linter/2019_09_test.cc new file mode 100644 index 0000000..0efcd9a --- /dev/null +++ b/test/linter/2019_09_test.cc @@ -0,0 +1,552 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_2019_09, enum_to_const_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "enum": [ 1 ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "const": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, const_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "string", + "const": "foo" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "const": "foo" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, content_media_type_without_encoding_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentMediaType": "application/json" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, content_schema_without_media_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentEncoding": "base64", + "contentSchema": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentEncoding": "base64" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, max_contains_without_contains_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "maxContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, max_contains_without_contains_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contains": true, + "maxContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contains": true, + "maxContains": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, min_contains_without_contains_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "minContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, min_contains_without_contains_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contains": true, + "minContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contains": true, + "minContains": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, then_without_if_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "then": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, then_without_if_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "if": true, + "then": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "if": true, + "then": true + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, else_without_if_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "else": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, else_without_if_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "if": true, + "else": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "if": true, + "else": true + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, unevaluated_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, unevaluated_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, unevaluated_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedProperties": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedProperties": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, unevaluated_items_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedItems": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, unevaluated_items_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedItems": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, unevaluated_items_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedItems": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "unevaluatedItems": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, content_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, content_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, content_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "items": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "items": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "items": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/2020_12_test.cc b/test/linter/2020_12_test.cc new file mode 100644 index 0000000..8082ffe --- /dev/null +++ b/test/linter/2020_12_test.cc @@ -0,0 +1,535 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_2020_12, enum_to_const_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "enum": [ 1 ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "const": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, const_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "const": "foo" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "const": "foo" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, content_media_type_without_encoding_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentMediaType": "application/json" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, content_schema_without_media_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentSchema": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, max_contains_without_contains_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "maxContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, max_contains_without_contains_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contains": true, + "maxContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contains": true, + "maxContains": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, min_contains_without_contains_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "minContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, min_contains_without_contains_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contains": true, + "minContains": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contains": true, + "minContains": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, then_without_if_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "then": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, then_without_if_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "if": true, + "then": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "if": true, + "then": true + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, else_without_if_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "else": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, else_without_if_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "if": true, + "else": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "if": true, + "else": true + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, unevaluated_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, unevaluated_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, unevaluated_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedProperties": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedProperties": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, unevaluated_items_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedItems": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, unevaluated_items_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedItems": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, unevaluated_items_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedItems": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedItems": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, content_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, content_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, content_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "contentEncoding": "base64", + "contentMediaType": "application/json", + "contentSchema": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "items": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "items": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "items": false + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/CMakeLists.txt b/test/linter/CMakeLists.txt new file mode 100644 index 0000000..b34cc8d --- /dev/null +++ b/test/linter/CMakeLists.txt @@ -0,0 +1,26 @@ +add_executable(sourcemeta_alterschema_linter_unit + 2020_12_test.cc + 2019_09_test.cc + draft7_test.cc + draft6_test.cc + draft4_test.cc + draft3_test.cc + draft2_test.cc + draft1_test.cc + draft0_test.cc + utils.h) + +noa_add_default_options(PRIVATE sourcemeta_alterschema_linter_unit) +target_link_libraries(sourcemeta_alterschema_linter_unit + PRIVATE GTest::gtest) +target_link_libraries(sourcemeta_alterschema_linter_unit + PRIVATE GTest::gtest_main) +target_link_libraries(sourcemeta_alterschema_linter_unit + PRIVATE sourcemeta::jsontoolkit::json) +target_link_libraries(sourcemeta_alterschema_linter_unit + PRIVATE sourcemeta::alterschema::engine) +target_link_libraries(sourcemeta_alterschema_linter_unit + PRIVATE sourcemeta::alterschema::linter) +add_test(NAME linter COMMAND sourcemeta_alterschema_linter_unit --gtest_brief=1) +set_target_properties(sourcemeta_alterschema_linter_unit + PROPERTIES FOLDER "Alterschema/linter") diff --git a/test/linter/draft0_test.cc b/test/linter/draft0_test.cc new file mode 100644 index 0000000..a789294 --- /dev/null +++ b/test/linter/draft0_test.cc @@ -0,0 +1,23 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft0, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft1_test.cc b/test/linter/draft1_test.cc new file mode 100644 index 0000000..9da3388 --- /dev/null +++ b/test/linter/draft1_test.cc @@ -0,0 +1,163 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft1, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "items": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "items": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft2_test.cc b/test/linter/draft2_test.cc new file mode 100644 index 0000000..074da2f --- /dev/null +++ b/test/linter/draft2_test.cc @@ -0,0 +1,163 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft2, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "items": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "items": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft3_test.cc b/test/linter/draft3_test.cc new file mode 100644 index 0000000..6243bdb --- /dev/null +++ b/test/linter/draft3_test.cc @@ -0,0 +1,163 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft3, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "items": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "items": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft4_test.cc b/test/linter/draft4_test.cc new file mode 100644 index 0000000..ceee5d6 --- /dev/null +++ b/test/linter/draft4_test.cc @@ -0,0 +1,163 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft4, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "items": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "items": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft6_test.cc b/test/linter/draft6_test.cc new file mode 100644 index 0000000..eac1008 --- /dev/null +++ b/test/linter/draft6_test.cc @@ -0,0 +1,200 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft6, enum_to_const_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "enum": [ 1 ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "const": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, const_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": "string", + "const": "foo" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "const": "foo" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "items": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "items": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft7_test.cc b/test/linter/draft7_test.cc new file mode 100644 index 0000000..a4fa5e4 --- /dev/null +++ b/test/linter/draft7_test.cc @@ -0,0 +1,291 @@ +#include + +#include + +#include "utils.h" + +TEST(Lint_draft7, enum_to_const_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "enum": [ 1 ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "const": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, const_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string", + "const": "foo" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "const": "foo" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, enum_with_type_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string", + "enum": [ "foo", "bar" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "enum": [ "foo", "bar" ] + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, single_type_array_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": [ "string" ] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, content_media_type_without_encoding_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "contentMediaType": "application/json" + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, then_without_if_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "then": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, then_without_if_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": true, + "then": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": true, + "then": true + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, else_without_if_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "else": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, else_without_if_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": true, + "else": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "if": true, + "else": true + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, additional_properties_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": true + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, additional_properties_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, additional_properties_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, items_schema_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, items_schema_default_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": {} + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, items_schema_default_3) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": { "type": "string" } + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": { "type": "string" } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, items_array_default_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "items": [] + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/utils.h b/test/linter/utils.h new file mode 100644 index 0000000..f4c9f64 --- /dev/null +++ b/test/linter/utils.h @@ -0,0 +1,20 @@ +#ifndef SOURCEMETA_ALTERSCHEMA_LINTER_TEST_UTILS_H_ +#define SOURCEMETA_ALTERSCHEMA_LINTER_TEST_UTILS_H_ + +#include +#include + +#define LINT_AND_FIX(document) \ + sourcemeta::alterschema::Bundle bundle; \ + sourcemeta::alterschema::add( \ + bundle, sourcemeta::alterschema::LinterCategory::Modernize); \ + sourcemeta::alterschema::add( \ + bundle, sourcemeta::alterschema::LinterCategory::AntiPattern); \ + sourcemeta::alterschema::add( \ + bundle, sourcemeta::alterschema::LinterCategory::Simplify); \ + sourcemeta::alterschema::add( \ + bundle, sourcemeta::alterschema::LinterCategory::Redundant); \ + bundle.apply(document, sourcemeta::jsontoolkit::default_schema_walker, \ + sourcemeta::jsontoolkit::official_resolver); + +#endif