From e3aa397f41edd1f86ccc518731e10ca97a0cd6c6 Mon Sep 17 00:00:00 2001 From: dhmemi <dhmemi@gmail.com> Date: Mon, 20 Nov 2023 20:48:18 +0800 Subject: [PATCH] fix: validate multipleOf fails on float-point value (#295) * fix: validate multipleOf fails on float-point value * make clang-tidy happy. * fix test case error when multipleOf is float but number is int * fix multiple of float number --- .gitignore | 1 + src/json-validator.cpp | 5 +++++ test/CMakeLists.txt | 4 ++++ test/issue-293.cpp | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 test/issue-293.cpp diff --git a/.gitignore b/.gitignore index aceaf81..bc9dd9f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ cmake-build-* venv env compile_commands.json +.vs/* diff --git a/src/json-validator.cpp b/src/json-validator.cpp index 6ede7c8..1fd0de1 100644 --- a/src/json-validator.cpp +++ b/src/json-validator.cpp @@ -864,7 +864,12 @@ class numeric : public schema bool violates_multiple_of(T x) const { double res = std::remainder(x, multipleOf_.second); + double multiple = std::fabs(x / multipleOf_.second); + if (multiple > 1) { + res = res / multiple; + } double eps = std::nextafter(x, 0) - static_cast<double>(x); + return std::fabs(res) > std::fabs(eps); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0345b34..b461df6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,6 +43,10 @@ add_executable(issue-98 issue-98.cpp) target_link_libraries(issue-98 nlohmann_json_schema_validator) add_test(NAME issue-98-erase-exception-unknown-keywords COMMAND issue-98) +add_executable(issue-293 issue-293.cpp) +target_link_libraries(issue-293 nlohmann_json_schema_validator) +add_test(NAME issue-293-float-point-error COMMAND issue-293) + # Unit test for string format checks add_executable(string-format-check-test string-format-check-test.cpp) target_include_directories(string-format-check-test PRIVATE ${PROJECT_SOURCE_DIR}/src/) diff --git a/test/issue-293.cpp b/test/issue-293.cpp new file mode 100644 index 0000000..dbfdac9 --- /dev/null +++ b/test/issue-293.cpp @@ -0,0 +1,32 @@ +#include "nlohmann/json-schema.hpp" + +using nlohmann::json_schema::json_validator; + +template <typename T> +int should_throw(const nlohmann::json &schema, T value) +{ + try { + json_validator(schema).validate(value); + } catch (const std::exception &ex) { + return 0; + } + return 1; +} + +int main(void) +{ + + json_validator({{"type", "number"}, {"multipleOf", 0.001}}).validate(0.3 - 0.2); + json_validator({{"type", "number"}, {"multipleOf", 3.3}}).validate(8.0 - 1.4); + json_validator({{"type", "number"}, {"multipleOf", 1000.01}}).validate((1000.03 - 0.02) * 15.0); + json_validator({{"type", "number"}, {"multipleOf", 0.001}}).validate(0.030999999999999993); + json_validator({{"type", "number"}, {"multipleOf", 0.100000}}).validate(1.9); + json_validator({{"type", "number"}, {"multipleOf", 100000.1}}).validate(9000009); + + int exc_count = 0; + exc_count += should_throw({{"type", "number"}, {"multipleOf", 0.001}}, 0.3 - 0.2005); + exc_count += should_throw({{"type", "number"}, {"multipleOf", 1000.02}}, (1000.03 - 0.02) * 15.0); + exc_count += should_throw({{"type", "number"}, {"multipleOf", 100000.11}}, 9000009); + + return exc_count; +}