Compare commits

..

No commits in common. "main" and "2.0.0" have entirely different histories.
main ... 2.0.0

157 changed files with 724 additions and 9241 deletions

View File

@ -1,14 +1,17 @@
BasedOnStyle: LLVM ---
BasedOnStyle: LLVM
AccessModifierOffset: -2
#AlignConsecutiveAssignments: true #AlignConsecutiveAssignments: true
#AlignConsecutiveDeclarations: true #AlignConsecutiveDeclarations: true
AllowShortFunctionsOnASingleLine: Inline AllowShortFunctionsOnASingleLine: Inline
BreakBeforeBraces: Linux BreakBeforeBraces: Linux
ColumnLimit: 0 ColumnLimit: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerAllOnOneLineOrOnePerLine: true
IndentWidth: 4 IndentWidth: 4
IndentPPDirectives: AfterHash IndentPPDirectives: AfterHash
ObjCBlockIndentWidth: 0 ObjCBlockIndentWidth: 0
SpaceAfterCStyleCast: true SpaceAfterCStyleCast: true
TabWidth: 4 TabWidth: 4
AccessModifierOffset: -4 AccessModifierOffset: -4
UseTab: ForIndentation UseTab: ForIndentation
...

View File

@ -1 +0,0 @@
1

4
.distro/.gitignore vendored
View File

@ -1,4 +0,0 @@
/main.fmf
/plans/main.fmf
/tests/main.fmf
*.tar.gz

View File

@ -1,61 +0,0 @@
Name: json-schema-validator
Summary: JSON schema validator for JSON for Modern C++
Version: 0.0.0
Release: %autorelease
License: MIT
URL: https://github.com/pboettch/json-schema-validator
Source: https://github.com/pboettch/json-schema-validator/archive/refs/tags/v%{version}.tar.gz
BuildRequires: ninja-build
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: json-devel
%description
Json schema validator library for C++ projects using nlohmann/json
%package devel
Summary: Development files for JSON schema validator
Requires: json-schema-validator%{?_isa} = %{version}-%{release}
Requires: json-devel
%description devel
Json schema validator development files for C++ projects using nlohmann/json
%prep
%autosetup -n json-schema-validator-%{version}
%build
%cmake \
-DJSON_VALIDATOR_SHARED_LIBS=ON \
-DJSON_VALIDATOR_INSTALL=ON \
-DJSON_VALIDATOR_BUILD_EXAMPLES=OFF \
-DJSON_VALIDATOR_BUILD_TESTS=ON
%cmake_build
%install
%cmake_install
%check
%ctest
%files
%doc README.md
%license LICENSE
%{_libdir}/libnlohmann_json_validator.so.*
%files devel
%{_libdir}/libnlohmann_json_validator.so
%{_includedir}/nlohmann/json-schema.hpp
%{_libdir}/cmake/nlohmann_json_schema_validator
%changelog
%autochangelog

View File

@ -1,3 +0,0 @@
Filters = [
"unknown-key",
]

View File

@ -1,12 +0,0 @@
summary:
Basic importing tests
prepare+:
- name: Include minimum fetching packages
how: install
package:
- git
discover+:
how: fmf
filter: "tag: import"
execute:
how: tmt

View File

@ -1,4 +0,0 @@
discover:
how: fmf
dist-git-source: true
path: .distro

View File

@ -1,14 +0,0 @@
summary:
Perform rpmlint and rpminspect tests
prepare:
- name: Download the source rpm
how: shell
script: cd /tmp && curl -O ${PACKIT_SRPM_URL}
- name: Download rpm packages
how: shell
script: cd /tmp && dnf download ${PACKIT_COPR_RPMS}
discover+:
how: fmf
filter: "tag: rpmlint"
execute:
how: tmt

View File

@ -1,7 +0,0 @@
summary:
Basic smoke tests
discover+:
how: fmf
filter: "tag: smoke"
execute:
how: tmt

View File

@ -1,15 +0,0 @@
# This is a simple project that tests using cmake to load the installed libraries
cmake_minimum_required(VERSION 3.14)
project(test_fetch_content LANGUAGES CXX)
FetchContent_Declare(nlohmann_json_schema_validator
GIT_REPOSITORY https://github.com/pboettch/json-schema-validator
GIT_TAG main
)
FetchContent_MakeAvailable(nlohmann_json_schema_validator)
if (NOT TARGET nlohmann_json_schema_validator::validator)
message(FATAL_ERROR "Missing target nlohmann_json_schema_validator::validator")
endif ()

View File

@ -1,11 +0,0 @@
# This is a simple project that tests using cmake to load the installed libraries
cmake_minimum_required(VERSION 3.14)
project(test_find_package LANGUAGES CXX)
set(CMAKE_FIND_DEBUG_MODE ON)
find_package(nlohmann_json_schema_validator REQUIRED)
if (NOT TARGET nlohmann_json_schema_validator::validator)
message(FATAL_ERROR "Missing target nlohmann_json_schema_validator::validator")
endif ()

View File

@ -1,11 +0,0 @@
# Common test variables
tag:
- import
tier: 0
path: /tests/import
# Define tests
/find_package:
test: ./test_find_package.sh
/FetchContent:
test: ./test_FetchContent.sh

View File

@ -1,4 +0,0 @@
#!/bin/bash -eux
tmp_dir=$(mktemp -d)
cmake -S ./FetchContent -B ${tmp_dir}

View File

@ -1,4 +0,0 @@
#!/bin/bash -eux
tmp_dir=$(mktemp -d)
cmake -S ./find_package -B ${tmp_dir}

View File

@ -1,13 +0,0 @@
# Common test variables
tag:
- rpmlint
tier: 0
path: /
# Define tests
/rpmlint:
summary: Rpmlint spec and rpmfiles
test: rpmlint -c packit.toml -r json-schema-validator.rpmlintrc ./*.spec /tmp/*.rpm
/rpminspect-rpms:
summary: Rpminspect the rpms
test: ls /tmp/*.rpm | xargs -L1 rpminspect-fedora -E metadata,disttag

View File

@ -1,9 +0,0 @@
# Common test variables
tag:
- smoke
tier: 0
path: /
# Define tests
/version:
test: echo "TODO: Write a minimum working example"

View File

@ -1,31 +0,0 @@
name: release
run-name: Release
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- "v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+"
jobs:
tests:
uses: ./.github/workflows/test.yaml
secrets: inherit
build_conan:
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v2.4.0
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub."
- run: echo "🔎 Branch name is ${{ github.ref }} and repository is ${{ github.repository }}."
- name: Clone json-schema-validator
uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: python -m pip install --upgrade conan
- run: conan config init
- run: conan profile update settings.compiler.libcxx=libstdc++11 default
- name: conan create package
run: conan create .

View File

@ -1,94 +0,0 @@
name: test
run-name: Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# Make it able to be used in other workflows
workflow_call:
defaults:
run:
shell: bash
jobs:
pre-commit:
name: Check pre-commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
- uses: pre-commit/action@v3.0.0
test:
name: Run ctests
needs: [ pre-commit ]
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
toolchain: [ gcc, llvm, intel ]
json_version: [ v3.11.2, v3.8.0 ]
experimental: [ false ]
include:
- toolchain: llvm
compiler_version: 15
- toolchain: gcc
compiler_version: latest
env:
NLOHMANN_JSON_VERSION: ${{ matrix.json_version }}
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v2.4.0
steps:
- name: Activate Intel compilers
# Not elegant, it will propagate all environment variable.
# Intel does not provide a way to output the environment variables to a file
# Note: PATH needs to be exported to GITHUB_PATH otherwise it can be overwritten
run: |
source /opt/intel/oneapi/setvars.sh
printenv >> $GITHUB_ENV
echo $PATH >> $GITHUB_PATH
if: matrix.toolchain == 'intel'
- name: Setup gcc toolchain
run: |
update-alternatives --install /usr/bin/g++ g++ $(which g++-${{ matrix.compiler_version }}) 999
if: matrix.compiler_version && matrix.toolchain == 'gcc'
- name: Setup llvm toolchain
run: |
update-alternatives --install /usr/bin/clang++ clang++ $(which clang++-${{ matrix.compiler_version }}) 999
if: matrix.compiler_version && matrix.toolchain == 'llvm'
- uses: actions/checkout@v3
# container version is < 3.25 which does not have workflows
- name: Get a working cmake version
uses: lukka/get-cmake@v3.25.2
- name: Run CMake ${{ matrix.toolchain }}-ci workflow with nlohmann/json version ${{ matrix.json_version }}
uses: lukka/run-cmake@v10.5
with:
workflowPreset: "${{ matrix.toolchain }}-ci"
coverage:
name: Run coverage tests
needs: [ test ]
runs-on: ubuntu-latest
container: ghcr.io/nlohmann/json-ci:v2.4.0
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
steps:
- uses: actions/checkout@v3
- name: Get latest cmake version
uses: lukka/get-cmake@latest
- name: Get test coverage
uses: lukka/run-cmake@v10.5
with:
workflowPreset: ci-coverage
- name: Get lcov data
uses: danielealbano/lcov-action@v3
with:
# Note lcov-action prepends and appends wild-cards *. Account for those
# https://github.com/danielealbano/lcov-action/issues/11
remove_patterns: /test/,/cmake-build*/
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage.info
verbose: true

6
.gitignore vendored
View File

@ -1,7 +1,3 @@
build*/ build*/
*.sw? *.sw?
cmake-build-*
venv
env
compile_commands.json
.vs/*

View File

@ -1,79 +0,0 @@
specfile_path: .distro/json-schema-validator.spec
files_to_sync:
- src: .distro/json-schema-validator.spec
dest: json-schema-validator.spec
- .packit.yaml
- src: .distro/json-schema-validator.rpmlintrc
dest: json-schema-validator.rpmlintrc
# tmt setup
- src: .distro/.fmf/
dest: .fmf/
- src: .distro/plans/
dest: plans/
filters:
- "- .distro/plans/main.fmf.dist-git"
- "- .distro/plans/rpmlint.fmf"
- src: .distro/plans/main.fmf.dist-git
dest: plans/main.fmf
upstream_package_name: json-schema-validator
downstream_package_name: json-schema-validator
update_release: false
upstream_tag_template: v{version}
jobs:
- job: copr_build
trigger: pull_request
owner: lecris
project: json-schema-validator
update_release: true
release_suffix: "{PACKIT_RPMSPEC_RELEASE}"
targets:
- fedora-development
- job: tests
trigger: pull_request
targets:
- fedora-development
fmf_path: .distro
- job: copr_build
trigger: commit
branch: main
owner: lecris
project: nightly
# TODO: Remove when upstream issue is resolved
# https://github.com/packit/packit/issues/1924
additional_repos:
- copr://@scikit-build/release
targets:
- fedora-development-x86_64
- fedora-latest-x86_64
- fedora-development-aarch64
- fedora-latest-aarch64
- job: copr_build
trigger: release
owner: lecris
project: release
targets:
- fedora-development-x86_64
- fedora-latest-x86_64
- fedora-development-aarch64
- fedora-latest-aarch64
- job: tests
trigger: commit
branch: main
targets:
- fedora-development
- fedora-latest
fmf_path: .distro
- job: propose_downstream
trigger: release
dist_git_branches:
- fedora-development
- fedora-latest
- job: koji_build
trigger: commit
dist_git_branches:
- fedora-all
- job: bodhi_update
trigger: commit
dist_git_branches:
- fedora-branched

View File

@ -1,33 +0,0 @@
repos:
- repo: https://github.com/Takishima/cmake-pre-commit-hooks
rev: v1.8.1
hooks:
- id: clang-format
args:
- '-i'
- id: clang-tidy
args:
# TODO: Remove when upstream issue is fixed
# https://gitlab.kitware.com/cmake/cmake/-/issues/24827
# https://github.com/Takishima/cmake-pre-commit-hooks/issues/63
- '-Bcmake-build-pre-commit'
- '--preset'
- 'pre-commit'
stages: [ manual ]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- repo: https://github.com/executablebooks/mdformat
rev: 0.7.16
hooks:
- id: mdformat
additional_dependencies:
- mdformat-gfm
- mdformat-tables
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.23.0
hooks:
- id: check-github-workflows

69
.travis.yml Normal file
View File

@ -0,0 +1,69 @@
#########################
# project configuration #
#########################
# C++ project
language: cpp
dist: trusty
sudo: required
group: edge
matrix:
include:
- os: linux
compiler: gcc
env: COMPILER=g++-4.9
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-5
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-5', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-6
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-7
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7', 'ninja-build']
script:
# get CMake and Ninja (only for systems with brew - macOS)
- |
if [[ (-x $(which brew)) ]]; then
brew update
brew install cmake ninja
brew upgrade cmake
fi
# make sure CXX is correctly set
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi
# show OS/compiler version
- uname -a
- cmake --version
- $CXX --version
# put json.hpp to nlohmann
- mkdir -p nlohmann && wget https://github.com/nlohmann/json/releases/download/v3.6.0/json.hpp -O nlohmann/json.hpp
# compile and execute unit tests
- mkdir -p build && cd build
- cmake .. -DNLOHMANN_JSON_DIR=.. ${CMAKE_OPTIONS} -GNinja && cmake --build . --config Release
- ctest -C Release -V -j
- cd ..

View File

@ -1,220 +1,119 @@
cmake_minimum_required(VERSION 3.14) project(json-schema-validator
# CMake version compatibility LANGUAGES CXX)
# TODO: Remove when bumping cmake >= 3.25
if (POLICY CMP0140)
# Enables: return(PROPAGATE)
cmake_policy(SET CMP0140 NEW)
endif ()
#[==============================================================================================[ set(PROJECT_VERSION 2.0.0)
# Basic project definition #
]==============================================================================================]
# TODO: CMake >= 3.19 can use string(JSON VERSION GET "${METADATA}" "version") to load from JSON cmake_minimum_required(VERSION 3.2)
set(PROJECT_VERSION 2.4.0)
# TODO: Version 3, rename the project and namespace to something more compact option(BUILD_TESTS "Build tests" ON)
project(nlohmann_json_schema_validator option(BUILD_EXAMPLES "Build examples" ON)
VERSION ${PROJECT_VERSION}
DESCRIPTION "Json validator for nlohmann::json library"
HOMEPAGE_URL "https://github.com/pboettch/json-schema-validator"
LANGUAGES CXX)
# TODO: Remove when bumping cmake >= 3.21
if (NOT DEFINED nlohmann_json_schema_validator_IS_TOP_LEVEL)
if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(PROJECT_IS_TOP_LEVEL ON)
else ()
set(PROJECT_IS_TOP_LEVEL OFF)
endif ()
endif ()
#[==============================================================================================[ # if used as a subdirectory just define a json-hpp-target as add_library(json-hpp INTERFACE)
# Options # # and associate the path to json.hpp via target_include_directories()
]==============================================================================================] if(NOT TARGET json-hpp)
set(NLOHMANN_JSON_DIR "" CACHE STRING "path to json.hpp")
option(JSON_VALIDATOR_INSTALL "JsonValidator: Install targets" ${PROJECT_IS_TOP_LEVEL}) # find nlohmann's json.hpp
option(JSON_VALIDATOR_BUILD_TESTS "JsonValidator: Build tests" ${PROJECT_IS_TOP_LEVEL}) find_path(JSON_HPP nlohmann/json.hpp
option(JSON_VALIDATOR_BUILD_EXAMPLES "JsonValidator: Build examples" ${PROJECT_IS_TOP_LEVEL}) PATHS
option(JSON_VALIDATOR_SHARED_LIBS "JsonValidator: Build as shared library" ${PROJECT_IS_TOP_LEVEL}) ${NLOHMANN_JSON_DIR}
option(JSON_VALIDATOR_TEST_COVERAGE "JsonValidator: Build with test coverage" OFF) ${CMAKE_BINARY_DIR}/${NLOHMANN_JSON_DIR}) # in case it is a relative path
mark_as_advanced(JSON_VALIDATOR_TEST_COVERAGE)
# Get a default JSON_FETCH_VERSION from environment variables to workaround the CI
if (DEFINED ENV{NLOHMANN_JSON_VERSION})
set(JSON_FETCH_VERSION_DEFAULT $ENV{NLOHMANN_JSON_VERSION})
else ()
set(JSON_FETCH_VERSION_DEFAULT v3.11.2)
endif ()
set(JSON_FETCH_VERSION ${JSON_FETCH_VERSION_DEFAULT} CACHE STRING "Fetch nlohmann::json version")
#[==============================================================================================[ # get the full, real path
# Project configuration # get_filename_component(NLOHMANN_JSON_REALPATH ${JSON_HPP} REALPATH)
]==============================================================================================]
# Include cmake modules if(NOT EXISTS ${NLOHMANN_JSON_REALPATH}/nlohmann/json.hpp)
include(FetchContent) message(FATAL_ERROR "please set NLOHMANN_JSON_DIR to a path in which NLohmann's json.hpp can be found. Looking for nlohmann/json.hpp in '${NLOHMANN_JSON_REALPATH}")
if (JSON_VALIDATOR_INSTALL) endif()
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
endif ()
# Default to release build # create an interface-library for simple cmake-linking
if (NOT CMAKE_BUILD_TYPE) add_library(json-hpp INTERFACE)
set(CMAKE_BUILD_TYPE Release) target_include_directories(json-hpp
endif () INTERFACE
${NLOHMANN_JSON_REALPATH})
endif()
# Enable cmake's BUILD_SHARED_LIBS # and one for the validator
set(BUILD_SHARED_LIBS ${nlohmann_json_schema_validator_SHARED_LIBS}) add_library(json-schema-validator
src/json-schema-draft7.json.cpp
src/json-uri.cpp
src/json-validator.cpp)
if (JSON_VALIDATOR_TEST_COVERAGE) set_target_properties(json-schema-validator
if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) PROPERTIES
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping") VERSION ${PROJECT_VERSION}
elseif (CMAKE_CXX_COMPILER_ID STREQUAL GNU) SOVERSION 1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
else ()
message(WARNING
"JsonValidator: Other toolchain coverage flags unknown.\n"
"Using --coverage as default")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
endif ()
endif ()
#[==============================================================================================[ install(TARGETS json-schema-validator
# External packages # LIBRARY DESTINATION lib
]==============================================================================================] ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin)
set(fetch_packages "") install(DIRECTORY src/
if (NOT TARGET nlohmann_json) DESTINATION include
# Fetch/Find nlohmann_json FILES_MATCHING PATTERN "*.h*")
# TODO: Remove when bumping cmake >= 3.24
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
FetchContent_Declare(nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json
GIT_TAG ${JSON_FETCH_VERSION}
FIND_PACKAGE_ARGS
)
list(APPEND fetch_packages nlohmann_json)
else ()
# Try to get system installed version
find_package(nlohmann_json QUIET)
if (NOT nlohmann_json_FOUND)
# If failed fetch the desired version
FetchContent_Declare(nlohmann_json
GIT_REPOSITORY https://github.com/nlohmann/json
GIT_TAG ${JSON_FETCH_VERSION}
)
list(APPEND fetch_packages nlohmann_json)
endif ()
endif ()
endif ()
# Handle configure flags target_include_directories(json-schema-validator
if (JSON_VALIDATOR_INSTALL) PUBLIC
# TODO: This is not ideal, this package should not be installing nlohmann::json ${CMAKE_CURRENT_SOURCE_DIR}/src)
# Currently required in order to satisfy cmake exporter
set(JSON_Install ON CACHE BOOL "")
endif ()
# Get all dependencies target_compile_features(json-schema-validator
FetchContent_MakeAvailable(${fetch_packages}) PUBLIC
if (JSON_VALIDATOR_INSTALL AND NOT nlohmann_json_FOUND AND JSON_Install) cxx_range_for) # for C++11 - flags
# TODO: This is not ideal
message(WARNING
"JsonValidator: No nlohmann::json found on the system and nlohmann_json_schema_validator will be installed\n"
"This will also install nlohmann::json in its typical installation path\n"
"This is not ideal because it might overwrite system installed")
endif ()
#[==============================================================================================[ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# Main definition # target_compile_options(json-schema-validator
]==============================================================================================] PRIVATE
-Wall -Wextra)
endif()
message(STATUS "JsonValidator: Configured for ${CMAKE_BUILD_TYPE}") target_link_libraries(json-schema-validator
if (DEFINED nlohmann_json_VERSION) PUBLIC
message(STATUS "JsonValidator: Using nlohmann/json version: ${nlohmann_json_VERSION}") json-hpp)
else () if(BUILD_SHARED_LIBS)
message(STATUS "JsonValidator: nlohmann_json_VERSION is not set. Possible value: ${JSON_FETCH_VERSION}") target_compile_definitions(json-schema-validator
endif () PRIVATE
-DJSON_SCHEMA_VALIDATOR_EXPORTS)
endif()
## Main targets # regex with boost if gcc < 4.9 - default is std::regex
add_library(nlohmann_json_schema_validator) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_library(nlohmann_json_schema_validator::validator ALIAS nlohmann_json_schema_validator) if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0")
set_target_properties(nlohmann_json_schema_validator PROPERTIES find_package(Boost COMPONENTS regex)
VERSION ${PROJECT_VERSION} if(NOT Boost_FOUND)
SOVERSION ${PROJECT_VERSION_MAJOR} message(STATUS "GCC less then 4.9 and boost-regex NOT found - no regex used")
EXPORT_NAME validator target_compile_definitions(json-schema-validator PRIVATE -DJSON_SCHEMA_NO_REGEX)
# TODO: Version 3, simplify the library name else()
# OUTPUT_NAME nlohmann_json_validator message(STATUS "GCC less then 4.9 and boost-regex FOUND - using boost::regex")
) target_compile_definitions(json-schema-validator PRIVATE -DJSON_SCHEMA_BOOST_REGEX)
target_include_directories(json-schema-validator PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(json-schema-validator PRIVATE ${Boost_LIBRARIES})
endif()
endif()
endif()
# Main definitions in here if(NOT TARGET json-hpp) # if used as a subdirectory do not install json-schema.hpp
add_subdirectory(src) install(
FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/json-schema.hpp
DESTINATION
${CMAKE_INSTALL_PREFIX}/include
)
endif()
# Enable examples if (BUILD_EXAMPLES)
# simple json-schema-validator-executable
add_executable(json-schema-validate app/json-schema-validate.cpp)
target_link_libraries(json-schema-validate json-schema-validator)
# Enable testings add_executable(readme-json-schema app/readme.cpp)
if (JSON_VALIDATOR_BUILD_TESTS) target_link_libraries(readme-json-schema json-schema-validator)
endif()
#add_subdirectory(ng)
if (BUILD_TESTS)
# test-zone
enable_testing() enable_testing()
add_subdirectory(test) add_subdirectory(test)
endif () endif()
if (JSON_VALIDATOR_BUILD_EXAMPLES)
add_subdirectory(example)
endif ()
#[==============================================================================================[
# Install or Export #
]==============================================================================================]
if (JSON_VALIDATOR_INSTALL)
# Note other install targets found in subdirectories
# Here mostly the cmake boilerplate are set
write_basic_package_version_file(nlohmann_json_schema_validatorConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
configure_package_config_file(cmake/nlohmann_json_schema_validatorConfig.cmake.in
nlohmann_json_schema_validatorConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nlohmann_json_schema_validator
)
# Install Targets files
export(EXPORT nlohmann_json_schema_validatorTargets
NAMESPACE nlohmann_json_schema_validator::
FILE nlohmann_json_schema_validatorTargets.cmake
)
install(EXPORT nlohmann_json_schema_validatorTargets
FILE nlohmann_json_schema_validatorTargets.cmake
NAMESPACE nlohmann_json_schema_validator::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nlohmann_json_schema_validator
COMPONENT nlohmann_json_schema_validator_Development
)
# Install cmake export files
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/nlohmann_json_schema_validatorConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/nlohmann_json_schema_validatorConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nlohmann_json_schema_validator
COMPONENT nlohmann_json_schema_validator_Development
)
endif ()
# Handle the project being included externally (e.g. FetchContent)
if (NOT PROJECT_IS_TOP_LEVEL)
# Export variables set in nlohmann_json_schema_validatorConfig.cmake
# TODO: Remove when bumping cmake >= 3.25
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.25)
return(PROPAGATE
nlohmann_json_schema_validator_VERSION
nlohmann_json_schema_validator_VERSION_MAJOR
nlohmann_json_schema_validator_VERSION_MINOR
nlohmann_json_schema_validator_VERSION_PATCH
nlohmann_json_schema_validator_VERSION_TWEAK
)
else ()
set(nlohmann_json_schema_validator_VERSION ${nlohmann_json_schema_validator_VERSION} PARENT_SCOPE)
set(nlohmann_json_schema_validator_VERSION_MAJOR ${nlohmann_json_schema_validator_VERSION_MAJOR} PARENT_SCOPE)
set(nlohmann_json_schema_validator_VERSION_MINOR ${nlohmann_json_schema_validator_VERSION_MINOR} PARENT_SCOPE)
set(nlohmann_json_schema_validator_VERSION_PATCH ${nlohmann_json_schema_validator_VERSION_PATCH} PARENT_SCOPE)
set(nlohmann_json_schema_validator_VERSION_TWEAK ${nlohmann_json_schema_validator_VERSION_TWEAK} PARENT_SCOPE)
endif ()
endif ()

View File

@ -1,7 +0,0 @@
{
"version": 6,
"include": [
"cmake/CMakePresets-defaults.json",
"cmake/CMakePresets-CI.json"
]
}

313
README.md
View File

@ -1,3 +1,4 @@
[![Build Status](https://travis-ci.org/pboettch/json-schema-validator.svg?branch=master)](https://travis-ci.org/pboettch/json-schema-validator) [![Build Status](https://travis-ci.org/pboettch/json-schema-validator.svg?branch=master)](https://travis-ci.org/pboettch/json-schema-validator)
# JSON schema validator for JSON for Modern C++ # JSON schema validator for JSON for Modern C++
@ -9,7 +10,7 @@ This is a C++ library for validating JSON documents based on a
[draft-7 of JSON Schema Validation](http://json-schema.org/schema). [draft-7 of JSON Schema Validation](http://json-schema.org/schema).
First a disclaimer: *It is work in progress and First a disclaimer: *It is work in progress and
contributions or hints or discussions are welcome.* contributions or hints or discussions are welcome.* Even though a 2.0.0 release is imminent.
Niels Lohmann et al develop a great JSON parser for C++ called [JSON for Modern Niels Lohmann et al develop a great JSON parser for C++ called [JSON for Modern
C++](https://github.com/nlohmann/json). This validator is based on this C++](https://github.com/nlohmann/json). This validator is based on this
@ -22,7 +23,7 @@ is rather simple.
Although significant changes have been done for the 2nd version Although significant changes have been done for the 2nd version
(a complete rewrite) the API is compatible with the 1.0.0 release. Except for (a complete rewrite) the API is compatible with the 1.0.0 release. Except for
the namespace which is now `nlohmann::json_schema`. the namespace which is now `nlohmann::json_schema.
Version **2** supports JSON schema draft 7, whereas 1 was supporting draft 4 Version **2** supports JSON schema draft 7, whereas 1 was supporting draft 4
only. Please update your schemas. only. Please update your schemas.
@ -41,128 +42,78 @@ messages if a JSON-document/instance does not comply to its schema.
By default this is done with exceptions thrown at the users with a helpful By default this is done with exceptions thrown at the users with a helpful
message telling what's wrong with the document while validating. message telling what's wrong with the document while validating.
Starting with **2.0.0** the user can pass a `json_schema::basic_error_handler`-derived With **2.0.0** the user can pass a `json_scheam::basic_error_handler`-derived
object along with the instance to validate to receive a callback each time object along with the instance to validate to receive a callback each time a
a validation error occurs and decide what to do (throwing, counting, collecting). validation error occurs and decide what to do (throwing, counting, collecting).
Another goal was to use Niels Lohmann's JSON-library. This is why the validator Another goal was to use Niels Lohmann's JSON-library. This is why the validator
lives in his namespace. lives in his namespace.
# Thread-safety
Instance validation is thread-safe and the same validator-object can be used by
different threads:
The validate method is `const` which indicates the object is not modified when
being called:
```C++
json json_validator::validate(const json &) const;
```
Validator-object creation however is not thread-safe. A validator has to be
created in one (main?) thread once.
# Weaknesses # Weaknesses
Numerical validation uses nlohmann-json's integer, unsigned and floating point Numerical validation uses nlohmann integer, unsigned and floating point types, depending on if
types, depending on if the schema type is "integer" or "number". Bignum the schema type is "integer" or "number". Bignum (i.e. arbitrary precision and
(i.e. arbitrary precision and range) is not supported at this time. range) is not supported at this time.
# Building Currently JSON-URI with "plain name fragments" are not supported: referring to an URI
with `$ref: "file.json#plain"` will not work.
This library is based on Niels Lohmann's JSON-library and thus has # How to use
a build-dependency to it.
Currently at least version **3.8.0** of NLohmann's JSON library The current state of the build-system needs at least version **3.6.0** of NLohmann's
is required. JSON library. It is looking for the `json.hpp` within a `nlohmann/`-path.
Various methods using CMake can be used to build this project. When build the library you need to provide the path to the directory where the include-file
is located as `nlohmann/json.hpp`.
## Build out-of-source ## Build
Do not run cmake inside the source-dir. Rather create a dedicated build-dir: ### Within a build-dir
```Bash ```Bash
git clone https://github.com/pboettch/json-schema-validator.git git clone https://github.com/pboettch/json-schema-validator.git
cd json-schema-validator cd json-schema-validator
mkdir build mkdir build
cd build cd build
cmake [..] cmake .. \
make -DNLOHMANN_JSON_DIR=<path/to/>nlohmann/json.hpp \
make install # if needed -DJSON_SCHEMA_TEST_SUITE_PATH=<path/to/JSON-Schema-test-suite> # optional
make # install
ctest # run unit, non-regression and test-suite tests ctest # run unit, non-regression and test-suite tests
``` ```
### As a subdirectory from within
## Building as shared library ```CMake
# create an interface-target called json-hpp
add_library(json-hpp INTERFACE)
target_include_directories(json-hpp
INTERFACE
path/to/nlohmann/json.hpp)
By default a static library is built. Shared libraries can be generated by using # set this path to schema-test-suite to get tests compiled - optional
set(JSON_SCHEMA_TEST_SUITE_PATH "path/to/json-schema-test-suite")
enable_testing() # if you want to inherit tests
add_subdirectory(path-to-this-project json-schema-validator)
```
### Building a shared library
By default a static library is built. Shared libraries are generated by using
the `BUILD_SHARED_LIBS`-cmake variable: the `BUILD_SHARED_LIBS`-cmake variable:
In your initial call to cmake simply add: In your initial call to cmake simply add:
```bash ```bash
cmake [..] -DBUILD_SHARED_LIBS=ON [..] cmake -DBUILD_SHARED_LIBS=ON
``` ```
## nlohmann-json integration
As nlohmann-json is a dependency, this library tries find it.
The cmake-configuration first checks if nlohmann-json is available as a cmake-target. This may be the case, because it is used as a submodule in a super-project which already provides and uses nlohmann-json.
Otherwise, it calls `find_package` for nlohmann-json and requires nlohmann-json to be installed on the system.
### Building with Hunter package manager
To enable access to nlohmann json library, Hunter can be used. Just run with `JSON_VALIDATOR_HUNTER=ON` option. No further dependencies needed
```bash
cmake [..] -DJSON_VALIDATOR_HUNTER=ON [..]
```
### Building as a CMake-subdirectory from within another project
Adding this library as a subdirectory to a parent project is one way of
building it.
If the parent project already used `find_package()` to find the CMake-package of nlohmann_json or includes it as a submodule likewise.
### Building directly, finding a CMake-package. (short)
When nlohmann-json has been installed, it provides files which allows
CMake's `find_package()` to be used.
This library is using this mechanism if `nlohmann_json::nlohmann_json`-target
does not exist.
### Install
Since version 2.1.0 this library can be installed and CMake-package-files will be
created accordingly. If the installation of nlohmann-json and this library
is done into default unix-system-paths CMake will be able to find this
library by simply doing:
```CMake
find_package(nlohmann_json_schema_validator REQUIRED)
```
and
```CMake
target_link_libraries(<your-target> [..] nlohmann_json_schema_validator)
```
to build and link.
## Code ## Code
See also `app/json-schema-validate.cpp`. See also `app/json-schema-validate.cpp`.
```C++ ```C++
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json-schema.hpp> #include "json-schema.hpp"
using nlohmann::json; using nlohmann::json;
using nlohmann::json_schema::json_validator; using nlohmann::json_schema::json_validator;
@ -199,56 +150,55 @@ static json good_person = {{"name", "Albert"}, {"age", 42}};
int main() int main()
{ {
/* json-parse the schema */ /* json-parse the schema */
json_validator validator; // create validator json_validator validator; // create validator
try { try {
validator.set_root_schema(person_schema); // insert root-schema validator.set_root_schema(person_schema); // insert root-schema
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n"; std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* json-parse the people - API of 1.0.0, default throwing error handler */ /* json-parse the people - API of 1.0.0, default throwing error handler */
for (auto &person : {bad_person, good_person}) { for (auto &person : {bad_person, good_person}) {
std::cout << "About to validate this person:\n" std::cout << "About to validate this person:\n"
<< std::setw(2) << person << std::endl; << std::setw(2) << person << std::endl;
try { try {
validator.validate(person); // validate the document - uses the default throwing error-handler validator.validate(person); // validate the document - uses the default throwing error-handler
std::cout << "Validation succeeded\n"; std::cout << "Validation succeeded\n";
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "Validation failed, here is why: " << e.what() << "\n"; std::cerr << "Validation failed, here is why: " << e.what() << "\n";
} }
} }
/* json-parse the people - with custom error handler */ /* json-parse the people - with custom error handler */
class custom_error_handler : public nlohmann::json_schema::basic_error_handler class custom_error_handler : public nlohmann::json_schema::basic_error_handler
{ {
void error(const nlohmann::json_pointer<nlohmann::basic_json<>> &pointer, const json &instance, void error(const std::string &path, const json &instance, const std::string &message) override
const std::string &message) override {
{ nlohmann::json_schema::basic_error_handler::error(path, instance, message);
nlohmann::json_schema::basic_error_handler::error(pointer, instance, message); std::cerr << "ERROR: '" << path << "' - '" << instance << "': " << message << "\n";
std::cerr << "ERROR: '" << pointer << "' - '" << instance << "': " << message << "\n"; }
} };
};
for (auto &person : {bad_person, good_person}) { for (auto &person : {bad_person, good_person}) {
std::cout << "About to validate this person:\n" std::cout << "About to validate this person:\n"
<< std::setw(2) << person << std::endl; << std::setw(2) << person << std::endl;
custom_error_handler err; custom_error_handler err;
validator.validate(person, err); // validate the document validator.validate(person, err); // validate the document
if (err) if (err)
std::cerr << "Validation failed\n"; std::cerr << "Validation failed\n";
else else
std::cout << "Validation succeeded\n"; std::cout << "Validation succeeded\n";
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
@ -263,104 +213,9 @@ cmake-variable `JSON_SCHEMA_TEST_SUITE_PATH` will enable the test-target(s).
All required tests are **OK**. All required tests are **OK**.
# Format # Additional features
Optionally JSON-schema-validator can validate predefined or user-defined formats. ## Default values
Therefore a format-checker-function can be provided by the user which is called by
the validator when a format-check is required (ie. the schema contains a format-field).
This is how the prototype looks like and how it can be passed to the validation-instance: The goal is to create an empty document, based on schema-defined
default-values, recursively populated.
```C++
static void my_format_checker(const std::string &format, const std::string &value)
{
if (format == "something") {
if (!check_value_for_something(value))
throw std::invalid_argument("value is not a good something");
} else
throw std::logic_error("Don't know how to validate " + format);
}
// when creating the validator
json_validator validator(nullptr, // or loader-callback
my_format_checker); // create validator
```
## Default Checker
The library contains a default-checker, which does some checks. It needs to be
provided manually to the constructor of the validator:
```C++
json_validator validator(loader, // or nullptr for no loader
nlohmann::json_schema::default_string_format_check);
```
Supported formats: `date-time, date, time, email, hostname, ipv4, ipv6, uuid, regex`
More formats can be added in `src/string-format-check.cpp`. Please contribute implementions for missing json schema draft formats.
## Default value processing
As a result of the validation, the library returns a json patch including the default values of the specified schema.
```C++
#include <iostream>
#include <nlohmann/json-schema.hpp>
using nlohmann::json;
using nlohmann::json_schema::json_validator;
static const json rectangle_schema = R"(
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "A rectangle",
"properties": {
"width": {
"$ref": "#/definitions/length",
"default": 20
},
"height": {
"$ref": "#/definitions/length"
}
},
"definitions": {
"length": {
"type": "integer",
"minimum": 1,
"default": 10
}
}
})"_json;
int main()
{
try {
json_validator validator{rectangle_schema};
/* validate empty json -> will be expanded by the default values defined in the schema */
json rectangle = "{}"_json;
const auto default_patch = validator.validate(rectangle);
rectangle = rectangle.patch(default_patch);
std::cout << rectangle.dump() << std::endl; // {"height":10,"width":20}
} catch (const std::exception &e) {
std::cerr << "Validation of schema failed: " << e.what() << "\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
```
The example above will output the specified default values `{"height":10,"width":20}` to stdout.
> Note that the default value specified in a `$ref` may be overridden by the current instance location. Also note that this behavior will break draft-7, but it is compliant to newer drafts (e.g. `2019-09` or `2020-12`).
# Contributing
This project uses [`pre-commit`](https://pre-commit.com/) to enforce style-checks. Please install and run it before
creating commits and making pull requests.
```console
$ pip install pre-commit
$ pre-commit install
```

View File

@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
*/ */
#include <nlohmann/json-schema.hpp> #include <json-schema.hpp>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
@ -24,12 +24,13 @@ static void usage(const char *name)
static void loader(const json_uri &uri, json &schema) static void loader(const json_uri &uri, json &schema)
{ {
std::string filename = "./" + uri.path(); std::string filename = "./" + uri.path();
std::ifstream lf(filename); std::fstream lf(filename);
if (!lf.good()) if (!lf.good())
throw std::invalid_argument("could not open " + uri.url() + " tried with " + filename); throw std::invalid_argument("could not open " + uri.url() + " tried with " + filename);
try { try {
lf >> schema; lf >> schema;
} catch (const std::exception &e) { } catch (std::exception &e) {
throw e; throw e;
} }
} }
@ -48,7 +49,7 @@ int main(int argc, char *argv[])
if (argc != 2) if (argc != 2)
usage(argv[0]); usage(argv[0]);
std::ifstream f(argv[1]); std::fstream f(argv[1]);
if (!f.good()) { if (!f.good()) {
std::cerr << "could not open " << argv[1] << " for reading\n"; std::cerr << "could not open " << argv[1] << " for reading\n";
usage(argv[0]); usage(argv[0]);
@ -58,20 +59,19 @@ int main(int argc, char *argv[])
json schema; json schema;
try { try {
f >> schema; f >> schema;
} catch (const std::exception &e) { } catch (std::exception &e) {
std::cerr << e.what() << " at " << f.tellg() << " - while parsing the schema\n"; std::cerr << e.what() << " at " << f.tellp() << " - while parsing the schema\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// 2) create the validator and // 2) create the validator and
json_validator validator(loader, json_validator validator(loader, [](const std::string &, const std::string &) {});
nlohmann::json_schema::default_string_format_check);
try { try {
// insert this schema as the root to the validator // insert this schema as the root to the validator
// this resolves remote-schemas, sub-schemas and references via the given loader-function // this resolves remote-schemas, sub-schemas and references via the given loader-function
validator.set_root_schema(schema); validator.set_root_schema(schema);
} catch (const std::exception &e) { } catch (std::exception &e) {
std::cerr << "setting root schema failed\n"; std::cerr << "setting root schema failed\n";
std::cerr << e.what() << "\n"; std::cerr << e.what() << "\n";
} }
@ -81,7 +81,7 @@ int main(int argc, char *argv[])
try { try {
std::cin >> document; std::cin >> document;
} catch (const std::exception &e) { } catch (std::exception &e) {
std::cerr << "json parsing failed: " << e.what() << " at offset: " << std::cin.tellg() << "\n"; std::cerr << "json parsing failed: " << e.what() << " at offset: " << std::cin.tellg() << "\n";
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@ -1,7 +1,7 @@
#include <iomanip>
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json-schema.hpp> #include "json-schema.hpp"
using nlohmann::json; using nlohmann::json;
using nlohmann::json_schema::json_validator; using nlohmann::json_schema::json_validator;
@ -12,25 +12,16 @@ static json person_schema = R"(
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"title": "A person", "title": "A person",
"properties": { "properties": {
"name": { "name": {
"description": "Name", "description": "Name",
"type": "string" "type": "string"
}, },
"age": { "age": {
"description": "Age of the person", "description": "Age of the person",
"type": "number", "type": "number",
"minimum": 2, "minimum": 2,
"maximum": 200 "maximum": 200
},
"address":{
"type": "object",
"properties":{
"street":{
"type": "string",
"default": "Abbey Road"
}
} }
}
}, },
"required": [ "required": [
"name", "name",
@ -43,8 +34,7 @@ static json person_schema = R"(
// The people are defined with brace initialization // The people are defined with brace initialization
static json bad_person = {{"age", 42}}; static json bad_person = {{"age", 42}};
static json good_person = {{"name", "Albert"}, {"age", 42}, {"address", {{"street", "Main Street"}}}}; static json good_person = {{"name", "Albert"}, {"age", 42}};
static json good_defaulted_person = {{"name", "Knut"}, {"age", 69}, {"address", {}}};
int main() int main()
{ {
@ -61,13 +51,12 @@ int main()
/* json-parse the people - API of 1.0.0, default throwing error handler */ /* json-parse the people - API of 1.0.0, default throwing error handler */
for (auto &person : {bad_person, good_person, good_defaulted_person}) { for (auto &person : {bad_person, good_person}) {
std::cout << "About to validate this person:\n" std::cout << "About to validate this person:\n"
<< std::setw(2) << person << std::endl; << std::setw(2) << person << std::endl;
try { try {
auto defaultPatch = validator.validate(person); // validate the document - uses the default throwing error-handler validator.validate(person); // validate the document - uses the default throwing error-handler
std::cout << "Validation succeeded\n"; std::cout << "Validation succeeded\n";
std::cout << "Patch with defaults: " << defaultPatch.dump(2) << std::endl;
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << "Validation failed, here is why: " << e.what() << "\n"; std::cerr << "Validation failed, here is why: " << e.what() << "\n";
} }
@ -83,6 +72,7 @@ int main()
} }
}; };
for (auto &person : {bad_person, good_person}) { for (auto &person : {bad_person, good_person}) {
std::cout << "About to validate this person:\n" std::cout << "About to validate this person:\n"
<< std::setw(2) << person << std::endl; << std::setw(2) << person << std::endl;

View File

@ -1,281 +0,0 @@
{
"version": 6,
"include": [
"CMakePresets-defaults.json"
],
"configurePresets": [
{
"name": "ci-base",
"hidden": true,
"generator": "Ninja",
"inherits": [
"default"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": {
"type": "STRING",
"value": "Debug"
},
"JSON_VALIDATOR_BUILD_TESTS": {
"type": "BOOL",
"value": true
},
"JSON_VALIDATOR_INSTALL": {
"type": "BOOL",
"value": false
},
"JSON_BuildTests": {
"type": "BOOL",
"value": false
}
},
"errors": {
"deprecated": true
}
},
{
"name": "gcc-ci",
"displayName": "Configure preset for GCC toolchain",
"inherits": [
"ci-base"
],
"binaryDir": "cmake-build-ci-gcc",
"cacheVariables": {
"CMAKE_CXX_COMPILER": {
"type": "FILEPATH",
"value": "g++"
},
"CMAKE_LINKER": {
"type": "FILEPATH",
"value": "ld"
}
}
},
{
"name": "intel-ci",
"displayName": "Configure preset for Intel toolchain",
"inherits": [
"ci-base"
],
"binaryDir": "cmake-build-ci-intel",
"cacheVariables": {
"CMAKE_CXX_COMPILER": {
"type": "FILEPATH",
"value": "icpx"
}
}
},
{
"name": "llvm-ci",
"displayName": "Configure preset for LLVM toolchain",
"inherits": [
"ci-base"
],
"binaryDir": "cmake-build-ci-llvm",
"cacheVariables": {
"CMAKE_CXX_COMPILER": {
"type": "FILEPATH",
"value": "clang++"
},
"CMAKE_LINKER": {
"type": "FILEPATH",
"value": "lld"
}
}
},
{
"name": "ci-coverage",
"displayName": "Configure preset for test coverage",
"inherits": [
"gcc-ci"
],
"binaryDir": "cmake-build-ci-coverage",
"errors": {
"deprecated": false
},
"cacheVariables": {
"JSON_VALIDATOR_TEST_COVERAGE": {
"type": "BOOL",
"value": true
}
}
},
{
"name": "pre-commit",
"displayName": "Configure preset for pre-commit checks",
"inherits": [
"default"
],
"binaryDir": "cmake-build-pre-commit",
"cacheVariables": {
"JSON_VALIDATOR_TEST_COVERAGE": {
"type": "BOOL",
"value": true
},
"JSON_VALIDATOR_INSTALL": {
"type": "BOOL",
"value": false
}
}
}
],
"buildPresets": [
{
"name": "ci-base",
"hidden": true,
"inherits": [
"default"
],
"cleanFirst": true
},
{
"name": "ci-coverage",
"displayName": "Build preset for test coverage",
"inherits": [
"ci-base"
],
"configurePreset": "ci-coverage"
},
{
"name": "gcc-ci",
"displayName": "Build preset for GCC toolchain",
"inherits": [
"ci-base"
],
"configurePreset": "gcc-ci"
},
{
"name": "intel-ci",
"displayName": "Build preset for Intel toolchain",
"inherits": [
"ci-base"
],
"configurePreset": "intel-ci"
},
{
"name": "llvm-ci",
"displayName": "Build preset for LLVM toolchain",
"inherits": [
"ci-base"
],
"configurePreset": "llvm-ci"
}
],
"testPresets": [
{
"name": "ci-base",
"hidden": true,
"inherits": [
"default"
],
"output": {
"outputOnFailure": true
}
},
{
"name": "ci-coverage",
"inherits": [
"default"
],
"configurePreset": "ci-coverage"
},
{
"name": "gcc-ci",
"displayName": "Test preset for GCC toolchain",
"inherits": [
"ci-base"
],
"configurePreset": "gcc-ci"
},
{
"name": "intel-ci",
"displayName": "Test preset for Intel toolchain",
"inherits": [
"ci-base"
],
"configurePreset": "intel-ci"
},
{
"name": "llvm-ci",
"displayName": "Test preset for LLVM toolchain",
"inherits": [
"ci-base"
],
"configurePreset": "llvm-ci"
}
],
"workflowPresets": [
{
"name": "gcc-ci",
"displayName": "CI test for GCC toolchain",
"steps": [
{
"type": "configure",
"name": "gcc-ci"
},
{
"type": "build",
"name": "gcc-ci"
},
{
"type": "test",
"name": "gcc-ci"
}
]
},
{
"name": "intel-ci",
"displayName": "CI test for Intel toolchain",
"steps": [
{
"type": "configure",
"name": "intel-ci"
},
{
"type": "build",
"name": "intel-ci"
},
{
"type": "test",
"name": "intel-ci"
}
]
},
{
"name": "llvm-ci",
"displayName": "CI test for LLVM toolchain",
"steps": [
{
"type": "configure",
"name": "llvm-ci"
},
{
"type": "build",
"name": "llvm-ci"
},
{
"type": "test",
"name": "llvm-ci"
}
]
},
{
"name": "ci-coverage",
"displayName": "Coverage tests",
"steps": [
{
"type": "configure",
"name": "ci-coverage"
},
{
"type": "build",
"name": "ci-coverage"
},
{
"type": "test",
"name": "ci-coverage"
}
]
}
]
}

View File

@ -1,50 +0,0 @@
{
"version": 6,
"configurePresets": [
{
"name": "default",
"displayName": "Default configuration preset",
"binaryDir": "cmake-build-release",
"cacheVariables": {
"CMAKE_BUILD_TYPE": {
"type": "STRING",
"value": "Release"
}
}
}
],
"buildPresets": [
{
"name": "default",
"displayName": "Default build preset",
"configurePreset": "default"
}
],
"testPresets": [
{
"name": "default",
"displayName": "Default test preset",
"configurePreset": "default"
}
],
"workflowPresets": [
{
"name": "default",
"displayName": "Default workflow",
"steps": [
{
"type": "configure",
"name": "default"
},
{
"type": "build",
"name": "default"
},
{
"type": "test",
"name": "default"
}
]
}
]
}

View File

@ -1,9 +0,0 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(nlohmann_json)
include("${CMAKE_CURRENT_LIST_DIR}/nlohmann_json_schema_validatorTargets.cmake")
check_required_components(
"nlohmann_json_schema_validator"
)

View File

@ -1,93 +0,0 @@
import os
import re
from conan import ConanFile
from conan.tools.cmake import cmake_layout, CMake, CMakeToolchain
from conans.tools import load
from conans import tools as ctools
def get_version():
try:
version = os.getenv('PROJECT_VERSION', None)
if version:
return version
content = load('CMakeLists.txt')
version = re.search('set\(PROJECT_VERSION (.*)\)', content).group(1)
return version.strip()
except:
return None
class JsonSchemaValidatorConan(ConanFile):
name = 'JsonSchemaValidator'
version = get_version()
url = 'https://github.com/pboettch/json-schema-validator'
license = 'MIT'
settings = 'os', 'compiler', 'build_type', 'arch'
options = {
'shared': [True, False],
'fPIC': [True, False],
'build_examples': [True, False],
'build_tests': [True, False],
'test_coverage': [True, False],
}
default_options = {
'shared': False,
'fPIC': True,
'build_examples': True,
'build_tests': False,
'test_coverage': False,
}
generators = 'CMakeDeps', 'CMakeToolchain', 'VirtualBuildEnv', 'VirtualRunEnv'
exports_sources = [
'CMakeLists.txt',
'conanfile.py',
'cmake/*',
'src/*',
'example/*',
'test/*',
]
requires = [
'nlohmann_json/3.11.2'
]
def generate(self):
tc = CMakeToolchain(self)
tc.variables['JSON_VALIDATOR_BUILD_EXAMPLES'] = self.options.build_examples
tc.variables['JSON_VALIDATOR_BUILD_TESTS'] = self.options.build_tests
tc.variables['JSON_VALIDATOR_SHARED_LIBS '] = self.options.shared
tc.variables['JSON_VALIDATOR_TEST_COVERAGE '] = self.options.test_coverage
tc.generate()
def layout(self):
cmake_layout(self)
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.verbose = True
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
def package_info(self):
includedir = os.path.join(self.package_folder, "include")
self.cpp_info.includedirs = [includedir]
libdir = os.path.join(self.package_folder, "lib")
self.cpp_info.libdirs = [libdir]
self.cpp_info.libs += ctools.collect_libs(self, libdir)
bindir = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bindir))
self.env_info.PATH.append(bindir)
self.user_info.VERSION = self.version

View File

@ -1,14 +0,0 @@
# simple nlohmann_json_schema_validator-executable
add_executable(json-schema-validate json-schema-validate.cpp)
target_link_libraries(json-schema-validate nlohmann_json_schema_validator)
add_executable(readme-json-schema readme.cpp)
target_link_libraries(readme-json-schema nlohmann_json_schema_validator)
add_executable(format-json-schema format.cpp)
target_link_libraries(format-json-schema nlohmann_json_schema_validator)
if (JSON_VALIDATOR_INSTALL)
install(TARGETS json-schema-validate readme-json-schema format-json-schema
DESTINATION ${CMAKE_INSTALL_BINDIR})
endif ()

View File

@ -1,54 +0,0 @@
#include <iostream>
#include <nlohmann/json-schema.hpp>
using nlohmann::json;
using nlohmann::json_schema::json_validator;
// The schema is defined based upon a string literal
static json uri_schema = R"(
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"myUri": {
"type":"string",
"format": "uri"
}
}
})"_json;
// The people are defined with brace initialization
static json good_uri = {{"myUri", "http://hostname.com/"}};
static json bad_uri = {{"myUri", "http:/hostname.com/"}};
static void uri_format_checker(const std::string &format, const std::string &value)
{
if (format == "uri") {
if (value.find("://") == std::string::npos)
throw std::invalid_argument("URI does not contain :// - invalid");
} else
throw std::logic_error("Don't know how to validate " + format);
}
int main()
{
json_validator validator(nullptr, uri_format_checker); // create validator
try {
validator.set_root_schema(uri_schema); // insert root-schema
} catch (const std::exception &e) {
std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
return EXIT_FAILURE;
}
validator.validate(good_uri);
try {
validator.validate(bad_uri);
} catch (const std::exception &e) {
std::cerr << "Validation expectedly failed, here is why: " << e.what() << "\n";
}
return EXIT_SUCCESS;
}

View File

@ -1,64 +0,0 @@
target_sources(nlohmann_json_schema_validator PRIVATE
smtp-address-validator.cpp
json-schema-draft7.json.cpp
json-uri.cpp
json-validator.cpp
json-patch.cpp
string-format-check.cpp
)
target_include_directories(nlohmann_json_schema_validator PUBLIC
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
set_target_properties(nlohmann_json_schema_validator PROPERTIES
PUBLIC_HEADER nlohmann/json-schema.hpp)
# TODO: Why would this need to be if guarded?
if (JSON_VALIDATOR_SHARED_LIBS)
target_compile_definitions(nlohmann_json_schema_validator PRIVATE
-DJSON_SCHEMA_VALIDATOR_EXPORTS)
endif ()
# TODO: Consider setting minimum cxx standard instead
target_compile_features(nlohmann_json_schema_validator PUBLIC
cxx_range_for) # for C++11 - flags
# TODO: This should be handled by the CI/presets, not the cmake
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
target_compile_options(nlohmann_json_schema_validator
PRIVATE
-Wall -Wextra -Wshadow)
endif ()
# TODO: gcc support for <4.9 should be removed
# regex with boost if gcc < 4.9 - default is std::regex
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9.0")
find_package(Boost COMPONENTS regex)
if (NOT Boost_FOUND)
message(STATUS "GCC less then 4.9 and boost-regex NOT found - no regex used")
target_compile_definitions(nlohmann_json_schema_validator PRIVATE -DJSON_SCHEMA_NO_REGEX)
else ()
message(STATUS "GCC less then 4.9 and boost-regex FOUND - using boost::regex")
target_compile_definitions(nlohmann_json_schema_validator PRIVATE -DJSON_SCHEMA_BOOST_REGEX)
target_include_directories(nlohmann_json_schema_validator PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(nlohmann_json_schema_validator PRIVATE ${Boost_LIBRARIES})
endif ()
endif ()
endif ()
target_link_libraries(nlohmann_json_schema_validator PUBLIC
nlohmann_json::nlohmann_json)
if (JSON_VALIDATOR_INSTALL)
# Normal installation target to system. When using scikit-build check python subdirectory
install(TARGETS nlohmann_json_schema_validator
EXPORT nlohmann_json_schema_validatorTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT nlohmann_json_schema_validator_Runtime
NAMELINK_COMPONENT nlohmann_json_schema_validator_Development
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT nlohmann_json_schema_validator_Development
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/nlohmann COMPONENT nlohmann_json_schema_validator_Development
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT nlohmann_json_schema_validator_Runtime)
endif ()

View File

@ -1,115 +0,0 @@
#include "json-patch.hpp"
#include <nlohmann/json-schema.hpp>
namespace
{
// originally from http://jsonpatch.com/, http://json.schemastore.org/json-patch
// with fixes
const nlohmann::json patch_schema = R"patch({
"title": "JSON schema for JSONPatch files",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "array",
"items": {
"oneOf": [
{
"additionalProperties": false,
"required": [ "value", "op", "path"],
"properties": {
"path" : { "$ref": "#/definitions/path" },
"op": {
"description": "The operation to perform.",
"type": "string",
"enum": [ "add", "replace", "test" ]
},
"value": {
"description": "The value to add, replace or test."
}
}
},
{
"additionalProperties": false,
"required": [ "op", "path"],
"properties": {
"path" : { "$ref": "#/definitions/path" },
"op": {
"description": "The operation to perform.",
"type": "string",
"enum": [ "remove" ]
}
}
},
{
"additionalProperties": false,
"required": [ "from", "op", "path" ],
"properties": {
"path" : { "$ref": "#/definitions/path" },
"op": {
"description": "The operation to perform.",
"type": "string",
"enum": [ "move", "copy" ]
},
"from": {
"$ref": "#/definitions/path",
"description": "A JSON Pointer path pointing to the location to move/copy from."
}
}
}
]
},
"definitions": {
"path": {
"description": "A JSON Pointer path.",
"type": "string"
}
}
})patch"_json;
} // namespace
namespace nlohmann
{
json_patch::json_patch(json &&patch)
: j_(std::move(patch))
{
validateJsonPatch(j_);
}
json_patch::json_patch(const json &patch)
: j_(std::move(patch))
{
validateJsonPatch(j_);
}
json_patch &json_patch::add(const json::json_pointer &ptr, json value)
{
j_.push_back(json{{"op", "add"}, {"path", ptr.to_string()}, {"value", std::move(value)}});
return *this;
}
json_patch &json_patch::replace(const json::json_pointer &ptr, json value)
{
j_.push_back(json{{"op", "replace"}, {"path", ptr.to_string()}, {"value", std::move(value)}});
return *this;
}
json_patch &json_patch::remove(const json::json_pointer &ptr)
{
j_.push_back(json{{"op", "remove"}, {"path", ptr.to_string()}});
return *this;
}
void json_patch::validateJsonPatch(json const &patch)
{
// static put here to have it created at the first usage of validateJsonPatch
static nlohmann::json_schema::json_validator patch_validator(patch_schema);
patch_validator.validate(patch);
for (auto const &op : patch)
json::json_pointer(op["path"].get<std::string>());
}
} // namespace nlohmann

View File

@ -1,41 +0,0 @@
#pragma once
#include <nlohmann/json.hpp>
#include <string>
namespace nlohmann
{
class JsonPatchFormatException : public std::exception
{
public:
explicit JsonPatchFormatException(std::string msg)
: ex_{std::move(msg)} {}
inline const char *what() const noexcept override final { return ex_.c_str(); }
private:
std::string ex_;
};
class json_patch
{
public:
json_patch() = default;
json_patch(json &&patch);
json_patch(const json &patch);
json_patch &add(const json::json_pointer &, json value);
json_patch &replace(const json::json_pointer &, json value);
json_patch &remove(const json::json_pointer &);
json &get_json() { return j_; }
const json &get_json() const { return j_; }
operator json() const { return j_; }
private:
json j_ = nlohmann::json::array();
static void validateJsonPatch(json const &patch);
};
} // namespace nlohmann

View File

@ -24,11 +24,11 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#ifdef NLOHMANN_JSON_VERSION_MAJOR #ifdef NLOHMANN_JSON_VERSION_MAJOR
# if (NLOHMANN_JSON_VERSION_MAJOR * 10000 + NLOHMANN_JSON_VERSION_MINOR * 100 + NLOHMANN_JSON_VERSION_PATCH) < 30800 # if (NLOHMANN_JSON_VERSION_MAJOR * 10000 + NLOHMANN_JSON_VERSION_MINOR * 100 + NLOHMANN_JSON_VERSION_PATCH) < 30600
# error "Please use this library with NLohmann's JSON version 3.8.0 or higher" # error "Please use this library with NLohmann's JSON version 3.6.0 or higher"
# endif # endif
#else #else
# error "expected existing NLOHMANN_JSON_VERSION_MAJOR preproc variable, please update to NLohmann's JSON 3.8.0" # error "expected existing NLOHMANN_JSON_VERSION_MAJOR preproc variable, please update to NLohmann's JSON 3.6.0"
#endif #endif
// make yourself a home - welcome to nlohmann's namespace // make yourself a home - welcome to nlohmann's namespace
@ -48,20 +48,18 @@ class JSON_SCHEMA_VALIDATOR_API json_uri
{ {
std::string urn_; std::string urn_;
std::string scheme_; std::string proto_;
std::string authority_; std::string hostname_;
std::string path_; std::string path_;
json::json_pointer pointer_;
json::json_pointer pointer_; // fragment part if JSON-Pointer
std::string identifier_; // fragment part if Locatation Independent ID
protected: protected:
// decodes a JSON uri and replaces all or part of the currently stored values // decodes a JSON uri and replaces all or part of the currently stored values
void update(const std::string &uri); void update(const std::string &uri);
std::tuple<std::string, std::string, std::string, std::string, std::string> as_tuple() const std::tuple<std::string, std::string, std::string, std::string, std::string> tie() const
{ {
return std::make_tuple(urn_, scheme_, authority_, path_, identifier_ != "" ? identifier_ : pointer_.to_string()); return std::tie(urn_, proto_, hostname_, path_, pointer_);
} }
public: public:
@ -70,23 +68,14 @@ public:
update(uri); update(uri);
} }
const std::string &scheme() const { return scheme_; } const std::string protocol() const { return proto_; }
const std::string &authority() const { return authority_; } const std::string hostname() const { return hostname_; }
const std::string &path() const { return path_; } const std::string path() const { return path_; }
const json::json_pointer &pointer() const { return pointer_; } const json::json_pointer pointer() const { return pointer_; }
const std::string &identifier() const { return identifier_; }
std::string fragment() const const std::string url() const { return location(); }
{ const std::string location() const;
if (identifier_ == "")
return pointer_.to_string();
else
return identifier_;
}
std::string url() const { return location(); }
std::string location() const;
static std::string escape(const std::string &); static std::string escape(const std::string &);
@ -102,9 +91,6 @@ public:
// append a pointer-field to the pointer-part of this uri // append a pointer-field to the pointer-part of this uri
json_uri append(const std::string &field) const json_uri append(const std::string &field) const
{ {
if (identifier_ != "")
return *this;
json_uri u = *this; json_uri u = *this;
u.pointer_ /= field; u.pointer_ /= field;
return u; return u;
@ -114,12 +100,12 @@ public:
friend bool operator<(const json_uri &l, const json_uri &r) friend bool operator<(const json_uri &l, const json_uri &r)
{ {
return l.as_tuple() < r.as_tuple(); return l.tie() < r.tie();
} }
friend bool operator==(const json_uri &l, const json_uri &r) friend bool operator==(const json_uri &l, const json_uri &r)
{ {
return l.as_tuple() == r.as_tuple(); return l.tie() == r.tie();
} }
friend std::ostream &operator<<(std::ostream &os, const json_uri &u); friend std::ostream &operator<<(std::ostream &os, const json_uri &u);
@ -132,7 +118,6 @@ extern json draft7_schema_builtin;
typedef std::function<void(const json_uri & /*id*/, json & /*value*/)> schema_loader; typedef std::function<void(const json_uri & /*id*/, json & /*value*/)> schema_loader;
typedef std::function<void(const std::string & /*format*/, const std::string & /*value*/)> format_checker; typedef std::function<void(const std::string & /*format*/, const std::string & /*value*/)> format_checker;
typedef std::function<void(const std::string & /*contentEncoding*/, const std::string & /*contentMediaType*/, const json & /*instance*/)> content_checker;
// Interface for validation error handlers // Interface for validation error handlers
class JSON_SCHEMA_VALIDATOR_API error_handler class JSON_SCHEMA_VALIDATOR_API error_handler
@ -156,11 +141,6 @@ public:
operator bool() const { return error_; } operator bool() const { return error_; }
}; };
/**
* Checks validity of JSON schema built-in string format specifiers like 'date-time', 'ipv4', ...
*/
void JSON_SCHEMA_VALIDATOR_API default_string_format_check(const std::string &format, const std::string &value);
class root_schema; class root_schema;
class JSON_SCHEMA_VALIDATOR_API json_validator class JSON_SCHEMA_VALIDATOR_API json_validator
@ -168,28 +148,19 @@ class JSON_SCHEMA_VALIDATOR_API json_validator
std::unique_ptr<root_schema> root_; std::unique_ptr<root_schema> root_;
public: public:
json_validator(schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr); json_validator(schema_loader = nullptr, format_checker = nullptr);
json_validator(const json &, schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr);
json_validator(json &&, schema_loader = nullptr, format_checker = nullptr, content_checker = nullptr);
json_validator(json_validator &&); json_validator(json_validator &&);
~json_validator();
json_validator &operator=(json_validator &&); json_validator &operator=(json_validator &&);
json_validator(json_validator const &) = delete; // insert and set thea root-schema
json_validator &operator=(json_validator const &) = delete;
~json_validator();
// insert and set the root-schema
void set_root_schema(const json &); void set_root_schema(const json &);
void set_root_schema(json &&);
// validate a json-document based on the root-schema // validate a json-document based on the root-schema
json validate(const json &) const; void validate(const json &) const;
// validate a json-document based on the root-schema with a custom error-handler // validate a json-document based on the root-schema with a custom error-handler
json validate(const json &, error_handler &, const json_uri &initial_uri = json_uri("#")) const; void validate(const json &, error_handler &) const;
}; };
} // namespace json_schema } // namespace json_schema

View File

@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
*/ */
#include <nlohmann/json-schema.hpp> #include "json-schema.hpp"
#include <sstream> #include <sstream>
@ -35,7 +35,7 @@ void json_uri::update(const std::string &uri)
} }
std::string hex = pointer.substr(pos + 1, 2); std::string hex = pointer.substr(pos + 1, 2);
char ascii = static_cast<char>(std::strtoul(hex.c_str(), nullptr, 16)); char ascii = (char) std::strtoul(hex.c_str(), nullptr, 16);
pointer.replace(pos, 3, 1, ascii); pointer.replace(pos, 3, 1, ascii);
pos--; pos--;
@ -44,15 +44,16 @@ void json_uri::update(const std::string &uri)
auto location = uri.substr(0, pointer_separator); auto location = uri.substr(0, pointer_separator);
if (location.size()) { // a location part has been found if (location.size()) { // a location part has been found
pointer_ = ""_json_pointer; // if a location is given, the pointer is emptied
// if it is an URN take it as it is // if it is an URN take it as it is
if (location.find("urn:") == 0) { if (location.find("urn:") == 0) {
urn_ = location; urn_ = location;
// and clear URL members // and clear URL members
scheme_ = ""; proto_ = "";
authority_ = ""; hostname_ = "";
path_ = ""; path_ = "";
} else { // it is an URL } else { // it is an URL
@ -64,13 +65,13 @@ void json_uri::update(const std::string &uri)
urn_ = ""; // clear URN-member if URL is parsed urn_ = ""; // clear URN-member if URL is parsed
scheme_ = location.substr(pos, proto - pos); proto_ = location.substr(pos, proto - pos);
pos = 3 + proto; // 3 == "://" pos = 3 + proto; // 3 == "://"
auto authority = location.find("/", pos); auto hostname = location.find("/", pos);
if (authority != std::string::npos) { // and the hostname (no proto without hostname) if (hostname != std::string::npos) { // and the hostname (no proto without hostname)
authority_ = location.substr(pos, authority - pos); hostname_ = location.substr(pos, hostname - pos);
pos = authority; pos = hostname;
} }
} }
@ -90,26 +91,20 @@ void json_uri::update(const std::string &uri)
} }
} }
pointer_ = ""_json_pointer; pointer_ = json::json_pointer(pointer);
identifier_ = "";
if (pointer[0] == '/')
pointer_ = json::json_pointer(pointer);
else
identifier_ = pointer;
} }
std::string json_uri::location() const const std::string json_uri::location() const
{ {
if (urn_.size()) if (urn_.size())
return urn_; return urn_;
std::stringstream s; std::stringstream s;
if (scheme_.size() > 0) if (proto_.size() > 0)
s << scheme_ << "://"; s << proto_ << "://";
s << authority_ s << hostname_
<< path_; << path_;
return s.str(); return s.str();
@ -119,12 +114,7 @@ std::string json_uri::to_string() const
{ {
std::stringstream s; std::stringstream s;
s << location() << " # "; s << location() << " # " << pointer_.to_string();
if (identifier_ == "")
s << pointer_.to_string();
else
s << identifier_;
return s.str(); return s.str();
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,792 +0,0 @@
/*
Snarfed from <https://github.com/gene-hightower/smtp-address-validator>
<http://opensource.org/licenses/MIT>:
Copyright (c) 2021 Gene Hightower
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "smtp-address-validator.hpp"
static const signed char _address_actions[] = {
0, 1, 0, 1, 1, 0};
static const short _address_key_offsets[] = {
0, 0, 24, 26, 50, 52, 54, 56,
58, 60, 62, 86, 103, 105, 107, 109,
111, 113, 115, 117, 134, 150, 161, 168,
176, 180, 181, 190, 195, 196, 201, 202,
207, 210, 213, 219, 222, 225, 228, 234,
237, 240, 243, 249, 252, 261, 270, 282,
293, 302, 311, 320, 328, 345, 353, 360,
367, 368, 375, 382, 389, 396, 397, 404,
411, 418, 425, 426, 433, 440, 447, 454,
455, 462, 469, 476, 483, 484, 491, 498,
505, 512, 513, 523, 531, 538, 545, 546,
552, 559, 566, 573, 581, 589, 597, 608,
618, 626, 634, 641, 649, 657, 665, 667,
673, 681, 689, 697, 699, 705, 713, 721,
729, 731, 737, 745, 753, 761, 763, 769,
777, 785, 793, 795, 802, 812, 821, 829,
837, 839, 848, 857, 865, 873, 875, 884,
893, 901, 909, 911, 920, 929, 937, 945,
947, 956, 965, 974, 983, 992, 1004, 1015,
1024, 1033, 1042, 1051, 1060, 1072, 1083, 1092,
1101, 1109, 1118, 1127, 1136, 1148, 1159, 1168,
1177, 1185, 1194, 1203, 1212, 1224, 1235, 1244,
1253, 1261, 1270, 1279, 1288, 1300, 1311, 1320,
1329, 1337, 1339, 1353, 1355, 1357, 1359, 1361,
1363, 1365, 1367, 1368, 1370, 1388, 0};
static const signed char _address_trans_keys[] = {
-32, -19, -16, -12, 34, 45, 61, 63,
-62, -33, -31, -17, -15, -13, 33, 39,
42, 43, 47, 57, 65, 90, 94, 126,
-128, -65, -32, -19, -16, -12, 33, 46,
61, 64, -62, -33, -31, -17, -15, -13,
35, 39, 42, 43, 45, 57, 63, 90,
94, 126, -96, -65, -128, -65, -128, -97,
-112, -65, -128, -65, -128, -113, -32, -19,
-16, -12, 33, 45, 61, 63, -62, -33,
-31, -17, -15, -13, 35, 39, 42, 43,
47, 57, 65, 90, 94, 126, -32, -19,
-16, -12, 91, -62, -33, -31, -17, -15,
-13, 48, 57, 65, 90, 97, 122, -128,
-65, -96, -65, -128, -65, -128, -97, -112,
-65, -128, -65, -128, -113, -32, -19, -16,
-12, 45, -62, -33, -31, -17, -15, -13,
48, 57, 65, 90, 97, 122, -32, -19,
-16, -12, -62, -33, -31, -17, -15, -13,
48, 57, 65, 90, 97, 122, 45, 48,
49, 50, 73, 51, 57, 65, 90, 97,
122, 45, 48, 57, 65, 90, 97, 122,
45, 58, 48, 57, 65, 90, 97, 122,
33, 90, 94, 126, 93, 45, 46, 58,
48, 57, 65, 90, 97, 122, 48, 49,
50, 51, 57, 46, 48, 49, 50, 51,
57, 46, 48, 49, 50, 51, 57, 93,
48, 57, 93, 48, 57, 53, 93, 48,
52, 54, 57, 93, 48, 53, 46, 48,
57, 46, 48, 57, 46, 53, 48, 52,
54, 57, 46, 48, 53, 46, 48, 57,
46, 48, 57, 46, 53, 48, 52, 54,
57, 46, 48, 53, 45, 46, 58, 48,
57, 65, 90, 97, 122, 45, 46, 58,
48, 57, 65, 90, 97, 122, 45, 46,
53, 58, 48, 52, 54, 57, 65, 90,
97, 122, 45, 46, 58, 48, 53, 54,
57, 65, 90, 97, 122, 45, 58, 80,
48, 57, 65, 90, 97, 122, 45, 58,
118, 48, 57, 65, 90, 97, 122, 45,
54, 58, 48, 57, 65, 90, 97, 122,
45, 58, 48, 57, 65, 90, 97, 122,
58, 33, 47, 48, 57, 59, 64, 65,
70, 71, 90, 94, 96, 97, 102, 103,
126, 58, 93, 48, 57, 65, 70, 97,
102, 58, 48, 57, 65, 70, 97, 102,
58, 48, 57, 65, 70, 97, 102, 58,
58, 48, 57, 65, 70, 97, 102, 58,
48, 57, 65, 70, 97, 102, 58, 48,
57, 65, 70, 97, 102, 58, 48, 57,
65, 70, 97, 102, 58, 58, 48, 57,
65, 70, 97, 102, 58, 48, 57, 65,
70, 97, 102, 58, 48, 57, 65, 70,
97, 102, 58, 48, 57, 65, 70, 97,
102, 58, 58, 48, 57, 65, 70, 97,
102, 58, 48, 57, 65, 70, 97, 102,
58, 48, 57, 65, 70, 97, 102, 58,
48, 57, 65, 70, 97, 102, 58, 58,
48, 57, 65, 70, 97, 102, 58, 48,
57, 65, 70, 97, 102, 58, 48, 57,
65, 70, 97, 102, 58, 48, 57, 65,
70, 97, 102, 58, 58, 48, 57, 65,
70, 97, 102, 58, 48, 57, 65, 70,
97, 102, 58, 48, 57, 65, 70, 97,
102, 58, 48, 57, 65, 70, 97, 102,
58, 48, 49, 50, 58, 51, 57, 65,
70, 97, 102, 46, 58, 48, 57, 65,
70, 97, 102, 58, 48, 57, 65, 70,
97, 102, 58, 48, 57, 65, 70, 97,
102, 58, 48, 57, 65, 70, 97, 102,
93, 48, 57, 65, 70, 97, 102, 93,
48, 57, 65, 70, 97, 102, 93, 48,
57, 65, 70, 97, 102, 46, 58, 48,
57, 65, 70, 97, 102, 46, 58, 48,
57, 65, 70, 97, 102, 46, 58, 48,
57, 65, 70, 97, 102, 46, 53, 58,
48, 52, 54, 57, 65, 70, 97, 102,
46, 58, 48, 53, 54, 57, 65, 70,
97, 102, 46, 58, 48, 57, 65, 70,
97, 102, 46, 58, 48, 57, 65, 70,
97, 102, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 58, 48, 57, 65, 70,
97, 102, 48, 49, 50, 93, 51, 57,
65, 70, 97, 102, 46, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
49, 50, 51, 57, 65, 70, 97, 102,
46, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 49, 50, 51, 57,
65, 70, 97, 102, 46, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
49, 50, 51, 57, 65, 70, 97, 102,
46, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 49, 50, 51, 57,
65, 70, 97, 102, 46, 58, 93, 48,
57, 65, 70, 97, 102, 46, 58, 93,
48, 57, 65, 70, 97, 102, 46, 58,
93, 48, 57, 65, 70, 97, 102, 46,
58, 93, 48, 57, 65, 70, 97, 102,
46, 53, 58, 93, 48, 52, 54, 57,
65, 70, 97, 102, 46, 58, 93, 48,
53, 54, 57, 65, 70, 97, 102, 46,
58, 93, 48, 57, 65, 70, 97, 102,
46, 58, 93, 48, 57, 65, 70, 97,
102, 46, 58, 93, 48, 57, 65, 70,
97, 102, 46, 58, 93, 48, 57, 65,
70, 97, 102, 46, 58, 93, 48, 57,
65, 70, 97, 102, 46, 53, 58, 93,
48, 52, 54, 57, 65, 70, 97, 102,
46, 58, 93, 48, 53, 54, 57, 65,
70, 97, 102, 46, 58, 93, 48, 57,
65, 70, 97, 102, 46, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
57, 65, 70, 97, 102, 46, 58, 93,
48, 57, 65, 70, 97, 102, 46, 58,
93, 48, 57, 65, 70, 97, 102, 46,
58, 93, 48, 57, 65, 70, 97, 102,
46, 53, 58, 93, 48, 52, 54, 57,
65, 70, 97, 102, 46, 58, 93, 48,
53, 54, 57, 65, 70, 97, 102, 46,
58, 93, 48, 57, 65, 70, 97, 102,
46, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 46, 58, 93, 48, 57, 65, 70,
97, 102, 46, 58, 93, 48, 57, 65,
70, 97, 102, 46, 58, 93, 48, 57,
65, 70, 97, 102, 46, 53, 58, 93,
48, 52, 54, 57, 65, 70, 97, 102,
46, 58, 93, 48, 53, 54, 57, 65,
70, 97, 102, 46, 58, 93, 48, 57,
65, 70, 97, 102, 46, 58, 93, 48,
57, 65, 70, 97, 102, 58, 93, 48,
57, 65, 70, 97, 102, 46, 58, 93,
48, 57, 65, 70, 97, 102, 46, 58,
93, 48, 57, 65, 70, 97, 102, 46,
58, 93, 48, 57, 65, 70, 97, 102,
46, 53, 58, 93, 48, 52, 54, 57,
65, 70, 97, 102, 46, 58, 93, 48,
53, 54, 57, 65, 70, 97, 102, 46,
58, 93, 48, 57, 65, 70, 97, 102,
46, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, 48, 57, 65, 70, 97,
102, 58, 93, -32, -19, -16, -12, 34,
92, -62, -33, -31, -17, -15, -13, 32,
126, -128, -65, -96, -65, -128, -65, -128,
-97, -112, -65, -128, -65, -128, -113, 64,
32, 126, -32, -19, -16, -12, 45, 46,
-62, -33, -31, -17, -15, -13, 48, 57,
65, 90, 97, 122, 0};
static const signed char _address_single_lengths[] = {
0, 8, 0, 8, 0, 0, 0, 0,
0, 0, 8, 5, 0, 0, 0, 0,
0, 0, 0, 5, 4, 5, 1, 2,
0, 1, 3, 3, 1, 3, 1, 3,
1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 1, 3, 3, 4, 3,
3, 3, 3, 2, 1, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 4, 2, 1, 1, 1, 0,
1, 1, 1, 2, 2, 2, 3, 2,
2, 2, 1, 2, 2, 2, 2, 0,
2, 2, 2, 2, 0, 2, 2, 2,
2, 0, 2, 2, 2, 2, 0, 2,
2, 2, 2, 1, 4, 3, 2, 2,
2, 3, 3, 2, 2, 2, 3, 3,
2, 2, 2, 3, 3, 2, 2, 2,
3, 3, 3, 3, 3, 4, 3, 3,
3, 3, 3, 3, 4, 3, 3, 3,
2, 3, 3, 3, 4, 3, 3, 3,
2, 3, 3, 3, 4, 3, 3, 3,
2, 3, 3, 3, 4, 3, 3, 3,
2, 2, 6, 0, 0, 0, 0, 0,
0, 0, 1, 0, 6, 0, 0};
static const signed char _address_range_lengths[] = {
0, 8, 1, 8, 1, 1, 1, 1,
1, 1, 8, 6, 1, 1, 1, 1,
1, 1, 1, 6, 6, 3, 3, 3,
2, 0, 3, 1, 0, 1, 0, 1,
1, 1, 2, 1, 1, 1, 2, 1,
1, 1, 2, 1, 3, 3, 4, 4,
3, 3, 3, 3, 8, 3, 3, 3,
0, 3, 3, 3, 3, 0, 3, 3,
3, 3, 0, 3, 3, 3, 3, 0,
3, 3, 3, 3, 0, 3, 3, 3,
3, 0, 3, 3, 3, 3, 0, 3,
3, 3, 3, 3, 3, 3, 4, 4,
3, 3, 3, 3, 3, 3, 0, 3,
3, 3, 3, 0, 3, 3, 3, 3,
0, 3, 3, 3, 3, 0, 3, 3,
3, 3, 0, 3, 3, 3, 3, 3,
0, 3, 3, 3, 3, 0, 3, 3,
3, 3, 0, 3, 3, 3, 3, 0,
3, 3, 3, 3, 3, 4, 4, 3,
3, 3, 3, 3, 4, 4, 3, 3,
3, 3, 3, 3, 4, 4, 3, 3,
3, 3, 3, 3, 4, 4, 3, 3,
3, 3, 3, 3, 4, 4, 3, 3,
3, 0, 4, 1, 1, 1, 1, 1,
1, 1, 0, 1, 6, 0, 0};
static const short _address_index_offsets[] = {
0, 0, 17, 19, 36, 38, 40, 42,
44, 46, 48, 65, 77, 79, 81, 83,
85, 87, 89, 91, 103, 114, 123, 128,
134, 137, 139, 146, 151, 153, 158, 160,
165, 168, 171, 176, 179, 182, 185, 190,
193, 196, 199, 204, 207, 214, 221, 230,
238, 245, 252, 259, 265, 275, 281, 286,
291, 293, 298, 303, 308, 313, 315, 320,
325, 330, 335, 337, 342, 347, 352, 357,
359, 364, 369, 374, 379, 381, 386, 391,
396, 401, 403, 411, 417, 422, 427, 429,
433, 438, 443, 448, 454, 460, 466, 474,
481, 487, 493, 498, 504, 510, 516, 519,
523, 529, 535, 541, 544, 548, 554, 560,
566, 569, 573, 579, 585, 591, 594, 598,
604, 610, 616, 619, 624, 632, 639, 645,
651, 654, 661, 668, 674, 680, 683, 690,
697, 703, 709, 712, 719, 726, 732, 738,
741, 748, 755, 762, 769, 776, 785, 793,
800, 807, 814, 821, 828, 837, 845, 852,
859, 865, 872, 879, 886, 895, 903, 910,
917, 923, 930, 937, 944, 953, 961, 968,
975, 981, 988, 995, 1002, 1011, 1019, 1026,
1033, 1039, 1042, 1053, 1055, 1057, 1059, 1061,
1063, 1065, 1067, 1069, 1071, 1084, 0};
static const short _address_cond_targs[] = {
4, 6, 7, 9, 186, 3, 3, 3,
2, 5, 8, 3, 3, 3, 3, 3,
0, 3, 0, 4, 6, 7, 9, 3,
10, 3, 11, 2, 5, 8, 3, 3,
3, 3, 3, 0, 2, 0, 2, 0,
2, 0, 5, 0, 5, 0, 5, 0,
4, 6, 7, 9, 3, 3, 3, 3,
2, 5, 8, 3, 3, 3, 3, 3,
0, 13, 15, 16, 18, 21, 12, 14,
17, 196, 196, 196, 0, 196, 0, 12,
0, 12, 0, 12, 0, 14, 0, 14,
0, 14, 0, 13, 15, 16, 18, 19,
12, 14, 17, 196, 196, 196, 0, 13,
15, 16, 18, 12, 14, 17, 196, 196,
196, 0, 22, 26, 44, 46, 48, 45,
23, 23, 0, 22, 23, 23, 23, 0,
22, 24, 23, 23, 23, 0, 25, 25,
0, 197, 0, 22, 27, 24, 23, 23,
23, 0, 28, 40, 42, 41, 0, 29,
0, 30, 36, 38, 37, 0, 31, 0,
25, 32, 34, 33, 0, 197, 33, 0,
197, 25, 0, 35, 197, 33, 25, 0,
197, 25, 0, 31, 37, 0, 31, 30,
0, 31, 39, 37, 30, 0, 31, 30,
0, 29, 41, 0, 29, 28, 0, 29,
43, 41, 28, 0, 29, 28, 0, 22,
27, 24, 45, 23, 23, 0, 22, 27,
24, 26, 23, 23, 0, 22, 27, 47,
24, 45, 26, 23, 23, 0, 22, 27,
24, 26, 23, 23, 23, 0, 22, 24,
49, 23, 23, 23, 0, 22, 24, 50,
23, 23, 23, 0, 22, 51, 24, 23,
23, 23, 0, 22, 52, 23, 23, 23,
0, 185, 25, 53, 25, 53, 25, 25,
53, 25, 0, 57, 197, 54, 54, 54,
0, 57, 55, 55, 55, 0, 57, 56,
56, 56, 0, 57, 0, 124, 58, 58,
58, 0, 62, 59, 59, 59, 0, 62,
60, 60, 60, 0, 62, 61, 61, 61,
0, 62, 0, 124, 63, 63, 63, 0,
67, 64, 64, 64, 0, 67, 65, 65,
65, 0, 67, 66, 66, 66, 0, 67,
0, 124, 68, 68, 68, 0, 72, 69,
69, 69, 0, 72, 70, 70, 70, 0,
72, 71, 71, 71, 0, 72, 0, 124,
73, 73, 73, 0, 77, 74, 74, 74,
0, 77, 75, 75, 75, 0, 77, 76,
76, 76, 0, 77, 0, 98, 78, 78,
78, 0, 82, 79, 79, 79, 0, 82,
80, 80, 80, 0, 82, 81, 81, 81,
0, 82, 0, 83, 91, 94, 98, 97,
123, 123, 0, 27, 87, 84, 84, 84,
0, 87, 85, 85, 85, 0, 87, 86,
86, 86, 0, 87, 0, 88, 88, 88,
0, 197, 89, 89, 89, 0, 197, 90,
90, 90, 0, 197, 25, 25, 25, 0,
27, 87, 92, 84, 84, 0, 27, 87,
93, 85, 85, 0, 27, 87, 86, 86,
86, 0, 27, 95, 87, 92, 96, 84,
84, 0, 27, 87, 93, 85, 85, 85,
0, 27, 87, 85, 85, 85, 0, 27,
87, 96, 84, 84, 0, 197, 99, 99,
99, 0, 103, 197, 100, 100, 100, 0,
103, 197, 101, 101, 101, 0, 103, 197,
102, 102, 102, 0, 103, 197, 0, 104,
104, 104, 0, 108, 197, 105, 105, 105,
0, 108, 197, 106, 106, 106, 0, 108,
197, 107, 107, 107, 0, 108, 197, 0,
109, 109, 109, 0, 113, 197, 110, 110,
110, 0, 113, 197, 111, 111, 111, 0,
113, 197, 112, 112, 112, 0, 113, 197,
0, 114, 114, 114, 0, 118, 197, 115,
115, 115, 0, 118, 197, 116, 116, 116,
0, 118, 197, 117, 117, 117, 0, 118,
197, 0, 119, 119, 119, 0, 87, 197,
120, 120, 120, 0, 87, 197, 121, 121,
121, 0, 87, 197, 122, 122, 122, 0,
87, 197, 0, 87, 84, 84, 84, 0,
125, 177, 180, 197, 183, 184, 184, 0,
27, 129, 197, 126, 126, 126, 0, 129,
197, 127, 127, 127, 0, 129, 197, 128,
128, 128, 0, 129, 197, 0, 130, 169,
172, 175, 176, 176, 0, 27, 134, 197,
131, 131, 131, 0, 134, 197, 132, 132,
132, 0, 134, 197, 133, 133, 133, 0,
134, 197, 0, 135, 161, 164, 167, 168,
168, 0, 27, 139, 197, 136, 136, 136,
0, 139, 197, 137, 137, 137, 0, 139,
197, 138, 138, 138, 0, 139, 197, 0,
140, 153, 156, 159, 160, 160, 0, 27,
144, 197, 141, 141, 141, 0, 144, 197,
142, 142, 142, 0, 144, 197, 143, 143,
143, 0, 144, 197, 0, 145, 146, 149,
152, 119, 119, 0, 27, 87, 197, 120,
120, 120, 0, 27, 87, 197, 147, 120,
120, 0, 27, 87, 197, 148, 121, 121,
0, 27, 87, 197, 122, 122, 122, 0,
27, 150, 87, 197, 147, 151, 120, 120,
0, 27, 87, 197, 148, 121, 121, 121,
0, 27, 87, 197, 121, 121, 121, 0,
27, 87, 197, 151, 120, 120, 0, 27,
144, 197, 154, 141, 141, 0, 27, 144,
197, 155, 142, 142, 0, 27, 144, 197,
143, 143, 143, 0, 27, 157, 144, 197,
154, 158, 141, 141, 0, 27, 144, 197,
155, 142, 142, 142, 0, 27, 144, 197,
142, 142, 142, 0, 27, 144, 197, 158,
141, 141, 0, 144, 197, 141, 141, 141,
0, 27, 139, 197, 162, 136, 136, 0,
27, 139, 197, 163, 137, 137, 0, 27,
139, 197, 138, 138, 138, 0, 27, 165,
139, 197, 162, 166, 136, 136, 0, 27,
139, 197, 163, 137, 137, 137, 0, 27,
139, 197, 137, 137, 137, 0, 27, 139,
197, 166, 136, 136, 0, 139, 197, 136,
136, 136, 0, 27, 134, 197, 170, 131,
131, 0, 27, 134, 197, 171, 132, 132,
0, 27, 134, 197, 133, 133, 133, 0,
27, 173, 134, 197, 170, 174, 131, 131,
0, 27, 134, 197, 171, 132, 132, 132,
0, 27, 134, 197, 132, 132, 132, 0,
27, 134, 197, 174, 131, 131, 0, 134,
197, 131, 131, 131, 0, 27, 129, 197,
178, 126, 126, 0, 27, 129, 197, 179,
127, 127, 0, 27, 129, 197, 128, 128,
128, 0, 27, 181, 129, 197, 178, 182,
126, 126, 0, 27, 129, 197, 179, 127,
127, 127, 0, 27, 129, 197, 127, 127,
127, 0, 27, 129, 197, 182, 126, 126,
0, 129, 197, 126, 126, 126, 0, 124,
197, 0, 188, 190, 191, 193, 194, 195,
187, 189, 192, 186, 0, 186, 0, 187,
0, 187, 0, 187, 0, 189, 0, 189,
0, 189, 0, 11, 0, 186, 0, 13,
15, 16, 18, 19, 20, 12, 14, 17,
196, 196, 196, 0, 0, 0, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42,
43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82,
83, 84, 85, 86, 87, 88, 89, 90,
91, 92, 93, 94, 95, 96, 97, 98,
99, 100, 101, 102, 103, 104, 105, 106,
107, 108, 109, 110, 111, 112, 113, 114,
115, 116, 117, 118, 119, 120, 121, 122,
123, 124, 125, 126, 127, 128, 129, 130,
131, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 142, 143, 144, 145, 146,
147, 148, 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, 159, 160, 161, 162,
163, 164, 165, 166, 167, 168, 169, 170,
171, 172, 173, 174, 175, 176, 177, 178,
179, 180, 181, 182, 183, 184, 185, 186,
187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 0};
static const signed char _address_cond_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 3, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 3, 0, 3, 0, 3,
0, 3, 0, 3, 0, 3, 0, 3,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 3, 1, 3, 0,
3, 0, 3, 0, 3, 0, 3, 0,
3, 0, 3, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 3, 0,
0, 0, 0, 0, 0, 0, 1, 1,
1, 3, 0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0, 0, 3,
0, 0, 0, 0, 0, 3, 0, 0,
3, 1, 3, 0, 0, 0, 0, 0,
0, 3, 0, 0, 0, 0, 3, 0,
3, 0, 0, 0, 0, 3, 0, 3,
0, 0, 0, 0, 3, 1, 0, 3,
1, 0, 3, 0, 1, 0, 0, 3,
1, 0, 3, 0, 0, 3, 0, 0,
3, 0, 0, 0, 0, 3, 0, 0,
3, 0, 0, 3, 0, 0, 3, 0,
0, 0, 0, 3, 0, 0, 3, 0,
0, 0, 0, 0, 0, 3, 0, 0,
0, 0, 0, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 3, 0, 0,
0, 0, 0, 0, 0, 3, 0, 0,
0, 0, 0, 0, 3, 0, 0, 0,
0, 0, 0, 3, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 3, 0, 1, 0, 0, 0,
3, 0, 0, 0, 0, 3, 0, 0,
0, 0, 3, 0, 3, 0, 0, 0,
0, 3, 0, 0, 0, 0, 3, 0,
0, 0, 0, 3, 0, 0, 0, 0,
3, 0, 3, 0, 0, 0, 0, 3,
0, 0, 0, 0, 3, 0, 0, 0,
0, 3, 0, 0, 0, 0, 3, 0,
3, 0, 0, 0, 0, 3, 0, 0,
0, 0, 3, 0, 0, 0, 0, 3,
0, 0, 0, 0, 3, 0, 3, 0,
0, 0, 0, 3, 0, 0, 0, 0,
3, 0, 0, 0, 0, 3, 0, 0,
0, 0, 3, 0, 3, 0, 0, 0,
0, 3, 0, 0, 0, 0, 3, 0,
0, 0, 0, 3, 0, 0, 0, 0,
3, 0, 3, 0, 0, 0, 0, 0,
0, 0, 3, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 3, 0, 0,
0, 0, 3, 0, 3, 0, 0, 0,
3, 1, 0, 0, 0, 3, 1, 0,
0, 0, 3, 1, 0, 0, 0, 3,
0, 0, 0, 0, 0, 3, 0, 0,
0, 0, 0, 3, 0, 0, 0, 0,
0, 3, 0, 0, 0, 0, 0, 0,
0, 3, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 3, 0,
0, 0, 0, 0, 3, 1, 0, 0,
0, 3, 0, 1, 0, 0, 0, 3,
0, 1, 0, 0, 0, 3, 0, 1,
0, 0, 0, 3, 0, 1, 3, 0,
0, 0, 3, 0, 1, 0, 0, 0,
3, 0, 1, 0, 0, 0, 3, 0,
1, 0, 0, 0, 3, 0, 1, 3,
0, 0, 0, 3, 0, 1, 0, 0,
0, 3, 0, 1, 0, 0, 0, 3,
0, 1, 0, 0, 0, 3, 0, 1,
3, 0, 0, 0, 3, 0, 1, 0,
0, 0, 3, 0, 1, 0, 0, 0,
3, 0, 1, 0, 0, 0, 3, 0,
1, 3, 0, 0, 0, 3, 0, 1,
0, 0, 0, 3, 0, 1, 0, 0,
0, 3, 0, 1, 0, 0, 0, 3,
0, 1, 3, 0, 0, 0, 0, 3,
0, 0, 0, 1, 0, 0, 0, 3,
0, 0, 1, 0, 0, 0, 3, 0,
1, 0, 0, 0, 3, 0, 1, 0,
0, 0, 3, 0, 1, 3, 0, 0,
0, 0, 0, 0, 3, 0, 0, 1,
0, 0, 0, 3, 0, 1, 0, 0,
0, 3, 0, 1, 0, 0, 0, 3,
0, 1, 3, 0, 0, 0, 0, 0,
0, 3, 0, 0, 1, 0, 0, 0,
3, 0, 1, 0, 0, 0, 3, 0,
1, 0, 0, 0, 3, 0, 1, 3,
0, 0, 0, 0, 0, 0, 3, 0,
0, 1, 0, 0, 0, 3, 0, 1,
0, 0, 0, 3, 0, 1, 0, 0,
0, 3, 0, 1, 3, 0, 0, 0,
0, 0, 0, 3, 0, 0, 1, 0,
0, 0, 3, 0, 0, 1, 0, 0,
0, 3, 0, 0, 1, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 3,
0, 0, 0, 1, 0, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 3,
0, 0, 1, 0, 0, 0, 3, 0,
0, 1, 0, 0, 0, 3, 0, 0,
1, 0, 0, 0, 3, 0, 0, 1,
0, 0, 0, 3, 0, 0, 0, 1,
0, 0, 0, 0, 3, 0, 0, 1,
0, 0, 0, 0, 3, 0, 0, 1,
0, 0, 0, 3, 0, 0, 1, 0,
0, 0, 3, 0, 1, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 3,
0, 0, 1, 0, 0, 0, 3, 0,
0, 1, 0, 0, 0, 3, 0, 0,
0, 1, 0, 0, 0, 0, 3, 0,
0, 1, 0, 0, 0, 0, 3, 0,
0, 1, 0, 0, 0, 3, 0, 0,
1, 0, 0, 0, 3, 0, 1, 0,
0, 0, 3, 0, 0, 1, 0, 0,
0, 3, 0, 0, 1, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 3,
0, 0, 0, 1, 0, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 0,
3, 0, 0, 1, 0, 0, 0, 3,
0, 0, 1, 0, 0, 0, 3, 0,
1, 0, 0, 0, 3, 0, 0, 1,
0, 0, 0, 3, 0, 0, 1, 0,
0, 0, 3, 0, 0, 1, 0, 0,
0, 3, 0, 0, 0, 1, 0, 0,
0, 0, 3, 0, 0, 1, 0, 0,
0, 0, 3, 0, 0, 1, 0, 0,
0, 3, 0, 0, 1, 0, 0, 0,
3, 0, 1, 0, 0, 0, 3, 0,
1, 3, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 3, 0, 3, 0,
3, 0, 3, 0, 3, 0, 3, 0,
3, 0, 3, 0, 3, 0, 3, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 3, 3, 0, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
3, 0, 0, 0};
static const short _address_eof_trans[] = {
1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093,
1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101,
1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109,
1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117,
1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125,
1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133,
1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141,
1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149,
1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157,
1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165,
1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173,
1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181,
1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189,
1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197,
1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205,
1206, 1207, 1208, 1209, 1210, 1211, 1212, 1213,
1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221,
1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229,
1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237,
1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245,
1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253,
1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261,
1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269,
1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277,
1278, 1279, 1280, 1281, 1282, 1283, 0};
static const int address_start = 1;
bool is_address(const char *p, const char *pe)
{
int cs = 0;
const char *eof = pe;
bool result = false;
{
cs = (int) address_start;
}
{
int _klen;
unsigned int _trans = 0;
const signed char *_keys;
const signed char *_acts;
unsigned int _nacts;
_resume : {
}
if (p == pe && p != eof)
goto _out;
if (p == eof) {
if (_address_eof_trans[cs] > 0) {
_trans = (unsigned int) _address_eof_trans[cs] - 1;
}
} else {
_keys = (_address_trans_keys + (_address_key_offsets[cs]));
_trans = (unsigned int) _address_index_offsets[cs];
_klen = (int) _address_single_lengths[cs];
if (_klen > 0) {
const signed char *_lower = _keys;
const signed char *_upper = _keys + _klen - 1;
const signed char *_mid;
while (1) {
if (_upper < _lower) {
_keys += _klen;
_trans += (unsigned int) _klen;
break;
}
_mid = _lower + ((_upper - _lower) >> 1);
if (((*(p))) < (*(_mid)))
_upper = _mid - 1;
else if (((*(p))) > (*(_mid)))
_lower = _mid + 1;
else {
_trans += (unsigned int) (_mid - _keys);
goto _match;
}
}
}
_klen = (int) _address_range_lengths[cs];
if (_klen > 0) {
const signed char *_lower = _keys;
const signed char *_upper = _keys + (_klen << 1) - 2;
const signed char *_mid;
while (1) {
if (_upper < _lower) {
_trans += (unsigned int) _klen;
break;
}
_mid = _lower + (((_upper - _lower) >> 1) & ~1);
if (((*(p))) < (*(_mid)))
_upper = _mid - 2;
else if (((*(p))) > (*(_mid + 1)))
_lower = _mid + 2;
else {
_trans += (unsigned int) ((_mid - _keys) >> 1);
break;
}
}
}
_match : {
}
}
cs = (int) _address_cond_targs[_trans];
if (_address_cond_actions[_trans] != 0) {
_acts = (_address_actions + (_address_cond_actions[_trans]));
_nacts = (unsigned int) (*(_acts));
_acts += 1;
while (_nacts > 0) {
switch ((*(_acts))) {
case 0: {
{
result = true;
}
break;
}
case 1: {
{
result = false;
}
break;
}
}
_nacts -= 1;
_acts += 1;
}
}
if (p == eof) {
if (cs >= 196)
goto _out;
} else {
if (cs != 0) {
p += 1;
goto _resume;
}
}
_out : {
}
}
return result;
}

View File

@ -1,34 +0,0 @@
#ifndef SMTP_ADDRESS_PARSER_HPP_INCLUDED
#define SMTP_ADDRESS_PARSER_HPP_INCLUDED
/*
Snarfed from <https://github.com/gene-hightower/smtp-address-validator>
<http://opensource.org/licenses/MIT>:
Copyright (c) 2021 Gene Hightower
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
bool is_address(const char *p, const char *pe);
#endif // SMTP_ADDRESS_PARSER_HPP_INCLUDED

View File

@ -1,414 +0,0 @@
#include <nlohmann/json-schema.hpp>
#include "smtp-address-validator.hpp"
#include <algorithm>
#include <exception>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#ifdef JSON_SCHEMA_BOOST_REGEX
# include <boost/regex.hpp>
# define REGEX_NAMESPACE boost
#elif defined(JSON_SCHEMA_NO_REGEX)
# define NO_STD_REGEX
#else
# include <regex>
# define REGEX_NAMESPACE std
#endif
/**
* Many of the RegExes are from @see http://jmrware.com/articles/2009/uri_regexp/URI_regex.html
*/
namespace
{
template <typename T>
void range_check(const T value, const T min, const T max)
{
if (!((value >= min) && (value <= max))) {
std::stringstream out;
out << "Value " << value << " should be in interval [" << min << "," << max << "] but is not!";
throw std::invalid_argument(out.str());
}
}
/** @see date_time_check */
void rfc3339_date_check(const std::string &value)
{
const static REGEX_NAMESPACE::regex dateRegex{R"(^([0-9]{4})\-([0-9]{2})\-([0-9]{2})$)"};
REGEX_NAMESPACE::smatch matches;
if (!REGEX_NAMESPACE::regex_match(value, matches, dateRegex)) {
throw std::invalid_argument(value + " is not a date string according to RFC 3339.");
}
const auto year = std::stoi(matches[1].str());
const auto month = std::stoi(matches[2].str());
const auto mday = std::stoi(matches[3].str());
const auto isLeapYear = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
range_check(month, 1, 12);
if (month == 2) {
range_check(mday, 1, isLeapYear ? 29 : 28);
} else if (month <= 7) {
range_check(mday, 1, month % 2 == 0 ? 30 : 31);
} else {
range_check(mday, 1, month % 2 == 0 ? 31 : 30);
}
}
/** @see date_time_check */
void rfc3339_time_check(const std::string &value)
{
const static REGEX_NAMESPACE::regex timeRegex{R"(^([0-9]{2})\:([0-9]{2})\:([0-9]{2})(\.[0-9]+)?(?:[Zz]|((?:\+|\-)[0-9]{2})\:([0-9]{2}))$)"};
REGEX_NAMESPACE::smatch matches;
if (!REGEX_NAMESPACE::regex_match(value, matches, timeRegex)) {
throw std::invalid_argument(value + " is not a time string according to RFC 3339.");
}
auto hour = std::stoi(matches[1].str());
auto minute = std::stoi(matches[2].str());
auto second = std::stoi(matches[3].str());
// const auto secfrac = std::stof( matches[4].str() );
range_check(hour, 0, 23);
range_check(minute, 0, 59);
int offsetHour = 0,
offsetMinute = 0;
/* don't check the numerical offset if time zone is specified as 'Z' */
if (!matches[5].str().empty()) {
offsetHour = std::stoi(matches[5].str());
offsetMinute = std::stoi(matches[6].str());
range_check(offsetHour, -23, 23);
range_check(offsetMinute, 0, 59);
if (offsetHour < 0)
offsetMinute *= -1;
}
/**
* @todo Could be made more exact by querying a leap second database and choosing the
* correct maximum in {58,59,60}. This current solution might match some invalid dates
* but it won't lead to false negatives. This only works if we know the full date, however
*/
auto day_minutes = hour * 60 + minute - (offsetHour * 60 + offsetMinute);
if (day_minutes < 0)
day_minutes += 60 * 24;
hour = day_minutes % 24;
minute = day_minutes / 24;
if (hour == 23 && minute == 59)
range_check(second, 0, 60); // possible leap-second
else
range_check(second, 0, 59);
}
/**
* @see https://tools.ietf.org/html/rfc3339#section-5.6
*
* @verbatim
* date-fullyear = 4DIGIT
* date-month = 2DIGIT ; 01-12
* date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
* ; month/year
* time-hour = 2DIGIT ; 00-23
* time-minute = 2DIGIT ; 00-59
* time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
* ; rules
* time-secfrac = "." 1*DIGIT
* time-numoffset = ("+" / "-") time-hour ":" time-minute
* time-offset = "Z" / time-numoffset
*
* partial-time = time-hour ":" time-minute ":" time-second
* [time-secfrac]
* full-date = date-fullyear "-" date-month "-" date-mday
* full-time = partial-time time-offset
*
* date-time = full-date "T" full-time
* @endverbatim
* NOTE: Per [ABNF] and ISO8601, the "T" and "Z" characters in this
* syntax may alternatively be lower case "t" or "z" respectively.
*/
void rfc3339_date_time_check(const std::string &value)
{
const static REGEX_NAMESPACE::regex dateTimeRegex{R"(^([0-9]{4}\-[0-9]{2}\-[0-9]{2})[Tt]([0-9]{2}\:[0-9]{2}\:[0-9]{2}(?:\.[0-9]+)?(?:[Zz]|(?:\+|\-)[0-9]{2}\:[0-9]{2}))$)"};
REGEX_NAMESPACE::smatch matches;
if (!REGEX_NAMESPACE::regex_match(value, matches, dateTimeRegex)) {
throw std::invalid_argument(value + " is not a date-time string according to RFC 3339.");
}
rfc3339_date_check(matches[1].str());
rfc3339_time_check(matches[2].str());
}
const std::string decOctet{R"((?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]))"}; // matches numbers 0-255
const std::string ipv4Address{"(?:" + decOctet + R"(\.){3})" + decOctet};
const std::string h16{R"([0-9A-Fa-f]{1,4})"};
const std::string h16Left{"(?:" + h16 + ":)"};
const std::string ipv6Address{
"(?:"
"(?:" +
h16Left + "{6}"
"|::" +
h16Left + "{5}"
"|(?:" +
h16 + ")?::" + h16Left + "{4}"
"|(?:" +
h16Left + "{0,1}" + h16 + ")?::" + h16Left + "{3}"
"|(?:" +
h16Left + "{0,2}" + h16 + ")?::" + h16Left + "{2}"
"|(?:" +
h16Left + "{0,3}" + h16 + ")?::" + h16Left +
"|(?:" + h16Left + "{0,4}" + h16 + ")?::"
")(?:" +
h16Left + h16 + "|" + ipv4Address + ")"
"|(?:" +
h16Left + "{0,5}" + h16 + ")?::" + h16 +
"|(?:" + h16Left + "{0,6}" + h16 + ")?::"
")"};
const std::string ipvFuture{R"([Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&'()*+,;=:]+)"};
const std::string regName{R"((?:[A-Za-z0-9\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*)"};
const std::string host{
"(?:"
R"(\[(?:)" +
ipv6Address + "|" + ipvFuture + R"()\])" +
"|" + ipv4Address +
"|" + regName +
")"};
const std::string uuid{R"([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})"};
// from http://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
const std::string hostname{R"(^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$)"};
bool is_ascii(std::string const &value)
{
for (auto ch : value) {
if (ch & 0x80) {
return false;
}
}
return true;
}
/**
* @see
*
* @verbatim
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
*
* hier-part = "//" authority path-abempty
* / path-absolute
* / path-rootless
* / path-empty
*
* URI-reference = URI / relative-ref
*
* absolute-URI = scheme ":" hier-part [ "?" query ]
*
* relative-ref = relative-part [ "?" query ] [ "#" fragment ]
*
* relative-part = "//" authority path-abempty
* / path-absolute
* / path-noscheme
* / path-empty
*
* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
*
* authority = [ userinfo "@" ] host [ ":" port ]
* userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
* host = IP-literal / IPv4address / reg-name
* port = *DIGIT
*
* IP-literal = "[" ( IPv6address / IPvFuture ) "]"
*
* IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
*
* IPv6address = 6( h16 ":" ) ls32
* / "::" 5( h16 ":" ) ls32
* / [ h16 ] "::" 4( h16 ":" ) ls32
* / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
* / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
* / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
* / [ *4( h16 ":" ) h16 ] "::" ls32
* / [ *5( h16 ":" ) h16 ] "::" h16
* / [ *6( h16 ":" ) h16 ] "::"
*
* h16 = 1*4HEXDIG
* ls32 = ( h16 ":" h16 ) / IPv4address
* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
* dec-octet = DIGIT ; 0-9
* / %x31-39 DIGIT ; 10-99
* / "1" 2DIGIT ; 100-199
* / "2" %x30-34 DIGIT ; 200-249
* / "25" %x30-35 ; 250-255
*
* reg-name = *( unreserved / pct-encoded / sub-delims )
*
* path = path-abempty ; begins with "/" or is empty
* / path-absolute ; begins with "/" but not "//"
* / path-noscheme ; begins with a non-colon segment
* / path-rootless ; begins with a segment
* / path-empty ; zero characters
*
* path-abempty = *( "/" segment )
* path-absolute = "/" [ segment-nz *( "/" segment ) ]
* path-noscheme = segment-nz-nc *( "/" segment )
* path-rootless = segment-nz *( "/" segment )
* path-empty = 0<pchar>
*
* segment = *pchar
* segment-nz = 1*pchar
* segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
* ; non-zero-length segment without any colon ":"
*
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
*
* query = *( pchar / "/" / "?" )
*
* fragment = *( pchar / "/" / "?" )
*
* pct-encoded = "%" HEXDIG HEXDIG
*
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* reserved = gen-delims / sub-delims
* gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*
* @endverbatim
* @see adapted from: https://github.com/jhermsmeier/uri.regex/blob/master/uri.regex
*
*/
void rfc3986_uri_check(const std::string &value)
{
const static std::string scheme{R"(([A-Za-z][A-Za-z0-9+\-.]*):)"};
const static std::string hierPart{
R"((?:(\/\/)(?:((?:[A-Za-z0-9\-._~!$&'()*+,;=:]|)"
R"(%[0-9A-Fa-f]{2})*)@)?((?:\[(?:(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|)"
R"(::(?:[0-9A-Fa-f]{1,4}:){5}|)"
R"((?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|)"
R"((?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|)"
R"((?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|)"
R"((?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|)"
R"((?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|)"
R"((?:(?:25[0-5]|2[0-4][0-9]|)"
R"([01]?[0-9][0-9]?)\.){3}(?:25[0-5]|)"
R"(2[0-4][0-9]|)"
R"([01]?[0-9][0-9]?))|)"
R"((?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|)"
R"((?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)|)"
R"([Vv][0-9A-Fa-f]+\.[A-Za-z0-9\-._~!$&'()*+,;=:]+)\]|)"
R"((?:(?:25[0-5]|)"
R"(2[0-4][0-9]|)"
R"([01]?[0-9][0-9]?)\.){3}(?:25[0-5]|)"
R"(2[0-4][0-9]|)"
R"([01]?[0-9][0-9]?)|)"
R"((?:[A-Za-z0-9\-._~!$&'()*+,;=]|)"
R"(%[0-9A-Fa-f]{2})*))(?::([0-9]*))?((?:\/(?:[A-Za-z0-9\-._~!$&'()*+,;=:@]|)"
R"(%[0-9A-Fa-f]{2})*)*)|)"
R"(\/((?:(?:[A-Za-z0-9\-._~!$&'()*+,;=:@]|)"
R"(%[0-9A-Fa-f]{2})+(?:\/(?:[A-Za-z0-9\-._~!$&'()*+,;=:@]|)"
R"(%[0-9A-Fa-f]{2})*)*)?)|)"
R"(((?:[A-Za-z0-9\-._~!$&'()*+,;=:@]|)"
R"(%[0-9A-Fa-f]{2})+(?:\/(?:[A-Za-z0-9\-._~!$&'()*+,;=:@]|)"
R"(%[0-9A-Fa-f]{2})*)*)|))"};
const static std::string query{R"((?:\?((?:[A-Za-z0-9\-._~!$&'()*+,;=:@\/?]|%[0-9A-Fa-f]{2})*))?)"};
const static std::string fragment{
R"((?:\#((?:[A-Za-z0-9\-._~!$&'()*+,;=:@\/?]|%[0-9A-Fa-f]{2})*))?)"};
const static std::string uriFormat{scheme + hierPart + query + fragment};
const static REGEX_NAMESPACE::regex uriRegex{uriFormat};
if (!REGEX_NAMESPACE::regex_match(value, uriRegex)) {
throw std::invalid_argument(value + " is not a URI string according to RFC 3986.");
}
}
} // namespace
namespace nlohmann
{
namespace json_schema
{
/**
* Checks validity for built-ins by converting the definitions given as ABNF in the linked RFC from
* @see https://json-schema.org/understanding-json-schema/reference/string.html#built-in-formats
* into regular expressions using @see https://www.msweet.org/abnf/ and some manual editing.
*
* @see https://json-schema.org/latest/json-schema-validation.html
*/
void default_string_format_check(const std::string &format, const std::string &value)
{
if (format == "date-time") {
rfc3339_date_time_check(value);
} else if (format == "date") {
rfc3339_date_check(value);
} else if (format == "time") {
rfc3339_time_check(value);
} else if (format == "uri") {
rfc3986_uri_check(value);
} else if (format == "email") {
if (!is_ascii(value)) {
throw std::invalid_argument(value + " contains non-ASCII values, not RFC 5321 compliant.");
}
if (!is_address(&*value.begin(), &*value.end())) {
throw std::invalid_argument(value + " is not a valid email according to RFC 5321.");
}
} else if (format == "idn-email") {
if (!is_address(&*value.begin(), &*value.end())) {
throw std::invalid_argument(value + " is not a valid idn-email according to RFC 6531.");
}
} else if (format == "hostname") {
static const REGEX_NAMESPACE::regex hostRegex{hostname};
if (!REGEX_NAMESPACE::regex_match(value, hostRegex)) {
throw std::invalid_argument(value + " is not a valid hostname according to RFC 3986 Appendix A.");
}
} else if (format == "ipv4") {
const static REGEX_NAMESPACE::regex ipv4Regex{"^" + ipv4Address + "$"};
if (!REGEX_NAMESPACE::regex_match(value, ipv4Regex)) {
throw std::invalid_argument(value + " is not an IPv4 string according to RFC 2673.");
}
} else if (format == "ipv6") {
static const REGEX_NAMESPACE::regex ipv6Regex{ipv6Address};
if (!REGEX_NAMESPACE::regex_match(value, ipv6Regex)) {
throw std::invalid_argument(value + " is not an IPv6 string according to RFC 5954.");
}
} else if (format == "uuid") {
static const REGEX_NAMESPACE::regex uuidRegex{uuid};
if (!REGEX_NAMESPACE::regex_match(value, uuidRegex)) {
throw std::invalid_argument(value + " is not an uuid string according to RFC 4122.");
}
} else if (format == "regex") {
try {
REGEX_NAMESPACE::regex re(value, std::regex::ECMAScript);
} catch (std::exception &exception) {
throw exception;
}
} else {
/* yet unsupported JSON schema draft 7 built-ins */
static const std::vector<std::string> jsonSchemaStringFormatBuiltIns{
"date-time", "time", "date", "email", "idn-email", "hostname", "idn-hostname", "ipv4", "ipv6", "uri",
"uri-reference", "iri", "iri-reference", "uri-template", "json-pointer", "relative-json-pointer", "regex"};
if (std::find(jsonSchemaStringFormatBuiltIns.begin(), jsonSchemaStringFormatBuiltIns.end(), format) != jsonSchemaStringFormatBuiltIns.end()) {
throw std::logic_error("JSON schema string format built-in " + format + " not yet supported. " +
"Please open an issue or use a custom format checker.");
}
throw std::logic_error("Don't know how to validate " + format);
}
}
} // namespace json_schema
} // namespace nlohmann

View File

@ -20,76 +20,9 @@ foreach(DIR ${TEST_DIRS})
endforeach() endforeach()
add_executable(uri uri.cpp) add_executable(uri uri.cpp)
target_link_libraries(uri nlohmann_json_schema_validator) target_link_libraries(uri json-schema-validator)
add_test(NAME uri COMMAND uri)
add_executable(errors errors.cpp) add_executable(errors errors.cpp)
target_link_libraries(errors nlohmann_json_schema_validator) target_link_libraries(errors json-schema-validator)
add_test(NAME errors COMMAND errors)
add_executable(issue-70 issue-70.cpp) add_test(NAME uri COMMAND uri)
target_link_libraries(issue-70 nlohmann_json_schema_validator)
add_test(NAME issue-70 COMMAND issue-70)
add_executable(issue-70-root-schema-constructor issue-70-root-schema-constructor.cpp)
target_link_libraries(issue-70-root-schema-constructor nlohmann_json_schema_validator)
add_test(NAME issue-70-root-schema-constructor COMMAND issue-70-root-schema-constructor)
add_executable(issue-25-default-values issue-25-default-values.cpp)
target_link_libraries(issue-25-default-values nlohmann_json_schema_validator)
add_test(NAME issue-25-default-values COMMAND issue-25-default-values)
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/)
target_link_libraries(string-format-check-test nlohmann_json_schema_validator)
add_test(NAME string-format-check-test COMMAND string-format-check-test)
# Unit test for json-patch
add_executable(json-patch json-patch.cpp)
target_include_directories(json-patch PRIVATE ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(json-patch nlohmann_json_schema_validator)
add_test(NAME json-patch COMMAND json-patch)
# Unit test for format checker fail at schema parsing time
add_executable(issue-117-format-error issue-117-format-error.cpp)
target_link_libraries(issue-117-format-error nlohmann_json_schema_validator)
add_test(NAME issue-117-format-error COMMAND issue-117-format-error)
add_executable(binary-validation binary-validation.cpp)
target_include_directories(binary-validation PRIVATE ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(binary-validation PRIVATE nlohmann_json_schema_validator)
add_test(NAME binary-validation COMMAND binary-validation)
add_executable(issue-149-entry-selection issue-149-entry-selection.cpp)
target_link_libraries(issue-149-entry-selection PRIVATE nlohmann_json_schema_validator)
add_test(NAME issue-149-entry-selection COMMAND issue-149-entry-selection)
add_executable(issue-189-default-values issue-189-default-values.cpp)
target_link_libraries(issue-189-default-values nlohmann_json_schema_validator)
add_test(NAME issue-189-default-values COMMAND issue-189-default-values)
add_executable(issue-229-oneof-default-values issue-229-oneof-default-values.cpp)
target_link_libraries(issue-229-oneof-default-values nlohmann_json_schema_validator)
add_test(NAME issue-229-oneof-default-values COMMAND issue-229-oneof-default-values)
add_executable(issue-243-root-default-values issue-243-root-default-values.cpp)
target_link_libraries(issue-243-root-default-values nlohmann_json_schema_validator)
add_test(NAME issue-243-root-default-values COMMAND issue-243-root-default-values)
add_executable(issue-255-error-message-limit-precision issue-255-error-message-limit-precision.cpp)
target_link_libraries(issue-255-error-message-limit-precision nlohmann_json_schema_validator)
add_test(NAME issue-255-error-message-limit-precision COMMAND issue-255-error-message-limit-precision)
add_executable(issue-105-verbose-combination-errors issue-105-verbose-combination-errors.cpp)
target_link_libraries(issue-105-verbose-combination-errors nlohmann_json_schema_validator)
add_test(NAME issue-105-verbose-combination-errors COMMAND issue-105-verbose-combination-errors)

View File

@ -15,7 +15,7 @@ endif()
if(JSON_SCHEMA_TEST_SUITE_PATH) if(JSON_SCHEMA_TEST_SUITE_PATH)
# json-schema-validator-tester # json-schema-validator-tester
add_executable(json-schema-test json-schema-test.cpp) add_executable(json-schema-test json-schema-test.cpp)
target_link_libraries(json-schema-test nlohmann_json_schema_validator) target_link_libraries(json-schema-test json-schema-validator)
target_compile_definitions(json-schema-test target_compile_definitions(json-schema-test
PRIVATE PRIVATE
JSON_SCHEMA_TEST_SUITE_PATH="${JSON_SCHEMA_TEST_SUITE_PATH}") JSON_SCHEMA_TEST_SUITE_PATH="${JSON_SCHEMA_TEST_SUITE_PATH}")
@ -50,18 +50,23 @@ if(JSON_SCHEMA_TEST_SUITE_PATH)
# some optional tests will fail # some optional tests will fail
set_tests_properties( set_tests_properties(
JSON-Suite::Optional::bignum JSON-Suite::Optional::bignum
JSON-Suite::Optional::non-bmp-regex JSON-Suite::Optional::content
JSON-Suite::Optional::float-overflow JSON-Suite::Optional::zeroTerminatedFloats
JSON-Suite::Optional::ecmascript-regex JSON-Suite::Optional::ecmascript-regex
JSON-Suite::Optional::Format::date-time
JSON-Suite::Optional::Format::date
JSON-Suite::Optional::Format::email
JSON-Suite::Optional::Format::idn-email
JSON-Suite::Optional::Format::idn-hostname JSON-Suite::Optional::Format::idn-hostname
JSON-Suite::Optional::Format::iri-reference JSON-Suite::Optional::Format::iri-reference
JSON-Suite::Optional::Format::iri JSON-Suite::Optional::Format::iri
JSON-Suite::Optional::Format::json-pointer JSON-Suite::Optional::Format::json-pointer
JSON-Suite::Optional::Format::relative-json-pointer JSON-Suite::Optional::Format::relative-json-pointer
JSON-Suite::Optional::Format::time
JSON-Suite::Optional::Format::uri-reference JSON-Suite::Optional::Format::uri-reference
JSON-Suite::Optional::Format::uri-template JSON-Suite::Optional::Format::uri-template
JSON-Suite::Optional::unicode JSON-Suite::Optional::Format::uri
PROPERTIES PROPERTIES
WILL_FAIL ON) WILL_FAIL ON)

View File

@ -6,7 +6,7 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
* *
*/ */
#include <nlohmann/json-schema.hpp> #include "json-schema.hpp"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
@ -16,6 +16,34 @@ using nlohmann::json;
using nlohmann::json_uri; using nlohmann::json_uri;
using nlohmann::json_schema::json_validator; using nlohmann::json_schema::json_validator;
static void format_check(const std::string &format, const std::string &value)
{
if (format == "hostname") {
// from http://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
std::regex re(R"(^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$)");
if (!std::regex_match(value, re))
throw std::invalid_argument(value + " is not a valid hostname.");
} else if (format == "ipv4") {
std::regex re(R"(^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$)");
if (!std::regex_match(value, re))
throw std::invalid_argument(value + " is not a IPv4-address.");
} else if (format == "ipv6") {
std::regex re(R"((([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])))");
if (!std::regex_match(value, re))
throw std::invalid_argument(value + " is not a IPv6-address.");
} else if (format == "regex") {
try {
std::regex re(value, std::regex::ECMAScript);
} catch (std::exception &e) {
throw e;
}
} else
throw std::logic_error("don't know how to validate " + format);
}
static void loader(const json_uri &uri, json &schema) static void loader(const json_uri &uri, json &schema)
{ {
if (uri.location() == "http://json-schema.org/draft-07/schema") { if (uri.location() == "http://json-schema.org/draft-07/schema") {
@ -39,50 +67,6 @@ static void loader(const json_uri &uri, json &schema)
} }
} }
// from here
// https://stackoverflow.com/a/34571089/880584
static std::string base64_decode(const std::string &in)
{
std::string out;
std::vector<int> T(256, -1);
for (int i = 0; i < 64; i++)
T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
unsigned val = 0;
int valb = -8;
for (uint8_t c : in) {
if (c == '=')
break;
if (T[c] == -1) {
throw std::invalid_argument("base64-decode: unexpected character in encode string: '" + std::string(1, c) + "'");
}
val = (val << 6) + T[c];
valb += 6;
if (valb >= 0) {
out.push_back(char((val >> valb) & 0xFF));
valb -= 8;
}
}
return out;
}
static void content(const std::string &contentEncoding, const std::string &contentMediaType, const json &instance)
{
std::string content = instance;
if (contentEncoding == "base64")
content = base64_decode(instance);
else if (contentEncoding != "")
throw std::invalid_argument("unable to check for contentEncoding '" + contentEncoding + "'");
if (contentMediaType == "application/json")
auto dummy = json::parse(content); // throws if conversion fails
else if (contentMediaType != "")
throw std::invalid_argument("unable to check for contentMediaType '" + contentMediaType + "'");
}
int main(void) int main(void)
{ {
json validation; // a validation case following the JSON-test-suite-schema json validation; // a validation case following the JSON-test-suite-schema
@ -105,9 +89,7 @@ int main(void)
const auto &schema = test_group["schema"]; const auto &schema = test_group["schema"];
json_validator validator(loader, json_validator validator(loader, format_check);
nlohmann::json_schema::default_string_format_check,
content);
validator.set_root_schema(schema); validator.set_root_schema(schema);

View File

@ -1,3 +0,0 @@
{
"type": "integer"
}

View File

@ -1,3 +0,0 @@
{
"type": "integer"
}

View File

@ -1,3 +1,3 @@
{ {
"type": "integer" "type": "integer"
} }

View File

@ -1,3 +1,3 @@
{ {
"type": "integer" "type": "integer"
} }

View File

@ -1,15 +0,0 @@
{
"$defs": {
"orNull": {
"anyOf": [
{
"type": "null"
},
{
"$ref": "#"
}
]
}
},
"type": "string"
}

View File

@ -2,12 +2,8 @@
"definitions": { "definitions": {
"orNull": { "orNull": {
"anyOf": [ "anyOf": [
{ {"type": "null"},
"type": "null" {"$ref": "#"}
},
{
"$ref": "#"
}
] ]
} }
}, },

View File

@ -1,11 +0,0 @@
{
"$id": "http://localhost:1234/ref-and-definitions.json",
"definitions": {
"inner": {
"properties": {
"bar": { "type": "string" }
}
}
},
"allOf": [ { "$ref": "#/definitions/inner" } ]
}

View File

@ -1,11 +0,0 @@
{
"$id": "http://localhost:1234/ref-and-defs.json",
"$defs": {
"inner": {
"properties": {
"bar": { "type": "string" }
}
}
},
"$ref": "#/$defs/inner"
}

View File

@ -1,10 +0,0 @@
{
"$defs": {
"integer": {
"type": "integer"
},
"refToInteger": {
"$ref": "#/$defs/integer"
}
}
}

View File

@ -1,8 +1,8 @@
{ {
"integer": { "integer": {
"type": "integer" "type": "integer"
}, },
"refToInteger": { "refToInteger": {
"$ref": "#/integer" "$ref": "#/integer"
} }
} }

View File

@ -19,7 +19,7 @@
] ]
}, },
{ {
"description": "when items is schema, additionalItems does nothing", "description": "items is schema, no additionalItems",
"schema": { "schema": {
"items": {}, "items": {},
"additionalItems": false "additionalItems": false
@ -33,24 +33,14 @@
] ]
}, },
{ {
"description": "array of items with no additionalItems permitted", "description": "array of items with no additionalItems",
"schema": { "schema": {
"items": [{}, {}, {}], "items": [{}, {}, {}],
"additionalItems": false "additionalItems": false
}, },
"tests": [ "tests": [
{ {
"description": "empty array", "description": "fewer number of items present",
"data": [ ],
"valid": true
},
{
"description": "fewer number of items present (1)",
"data": [ 1 ],
"valid": true
},
{
"description": "fewer number of items present (2)",
"data": [ 1, 2 ], "data": [ 1, 2 ],
"valid": true "valid": true
}, },
@ -93,57 +83,5 @@
"valid": true "valid": true
} }
] ]
},
{
"description": "additionalItems should not look in applicators, valid case",
"schema": {
"allOf": [
{ "items": [ { "type": "integer" } ] }
],
"additionalItems": { "type": "boolean" }
},
"tests": [
{
"description": "items defined in allOf are not examined",
"data": [ 1, null ],
"valid": true
}
]
},
{
"description": "additionalItems should not look in applicators, invalid case",
"schema": {
"allOf": [
{ "items": [ { "type": "integer" }, { "type": "string" } ] }
],
"items": [ {"type": "integer" } ],
"additionalItems": { "type": "boolean" }
},
"tests": [
{
"description": "items defined in allOf are not examined",
"data": [ 1, "hello" ],
"valid": false
}
]
},
{
"description": "items validation adjusts the starting index for additionalItems",
"schema": {
"items": [ { "type": "string" } ],
"additionalItems": { "type": "integer" }
},
"tests": [
{
"description": "valid items",
"data": [ "x", 2, 3 ],
"valid": true
},
{
"description": "wrong type of second item",
"data": [ "x", "y" ],
"valid": false
}
]
} }
] ]

View File

@ -124,7 +124,7 @@
}, },
"tests": [ "tests": [
{ {
"description": "properties defined in allOf are not examined", "description": "properties defined in allOf are not allowed",
"data": {"foo": 1, "bar": true}, "data": {"foo": 1, "bar": true},
"valid": false "valid": false
} }

View File

@ -214,81 +214,5 @@
"valid": false "valid": false
} }
] ]
},
{
"description": "nested allOf, to check validation semantics",
"schema": {
"allOf": [
{
"allOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
},
{
"description": "allOf combined with anyOf, oneOf",
"schema": {
"allOf": [ { "multipleOf": 2 } ],
"anyOf": [ { "multipleOf": 3 } ],
"oneOf": [ { "multipleOf": 5 } ]
},
"tests": [
{
"description": "allOf: false, anyOf: false, oneOf: false",
"data": 1,
"valid": false
},
{
"description": "allOf: false, anyOf: false, oneOf: true",
"data": 5,
"valid": false
},
{
"description": "allOf: false, anyOf: true, oneOf: false",
"data": 3,
"valid": false
},
{
"description": "allOf: false, anyOf: true, oneOf: true",
"data": 15,
"valid": false
},
{
"description": "allOf: true, anyOf: false, oneOf: false",
"data": 2,
"valid": false
},
{
"description": "allOf: true, anyOf: false, oneOf: true",
"data": 10,
"valid": false
},
{
"description": "allOf: true, anyOf: true, oneOf: false",
"data": 6,
"valid": false
},
{
"description": "allOf: true, anyOf: true, oneOf: true",
"data": 30,
"valid": true
}
]
} }
] ]

View File

@ -159,57 +159,5 @@
"valid": true "valid": true
} }
] ]
},
{
"description": "nested anyOf, to check validation semantics",
"schema": {
"anyOf": [
{
"anyOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
},
{
"description": "nested anyOf, to check validation semantics",
"schema": {
"anyOf": [
{
"anyOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
} }
] ]

View File

@ -82,261 +82,5 @@
"valid": false "valid": false
} }
] ]
},
{
"description": "const with false does not match 0",
"schema": {"const": false},
"tests": [
{
"description": "false is valid",
"data": false,
"valid": true
},
{
"description": "integer zero is invalid",
"data": 0,
"valid": false
},
{
"description": "float zero is invalid",
"data": 0.0,
"valid": false
}
]
},
{
"description": "const with true does not match 1",
"schema": {"const": true},
"tests": [
{
"description": "true is valid",
"data": true,
"valid": true
},
{
"description": "integer one is invalid",
"data": 1,
"valid": false
},
{
"description": "float one is invalid",
"data": 1.0,
"valid": false
}
]
},
{
"description": "const with [false] does not match [0]",
"schema": {"const": [false]},
"tests": [
{
"description": "[false] is valid",
"data": [false],
"valid": true
},
{
"description": "[0] is invalid",
"data": [0],
"valid": false
},
{
"description": "[0.0] is invalid",
"data": [0.0],
"valid": false
}
]
},
{
"description": "const with [true] does not match [1]",
"schema": {"const": [true]},
"tests": [
{
"description": "[true] is valid",
"data": [true],
"valid": true
},
{
"description": "[1] is invalid",
"data": [1],
"valid": false
},
{
"description": "[1.0] is invalid",
"data": [1.0],
"valid": false
}
]
},
{
"description": "const with {\"a\": false} does not match {\"a\": 0}",
"schema": {"const": {"a": false}},
"tests": [
{
"description": "{\"a\": false} is valid",
"data": {"a": false},
"valid": true
},
{
"description": "{\"a\": 0} is invalid",
"data": {"a": 0},
"valid": false
},
{
"description": "{\"a\": 0.0} is invalid",
"data": {"a": 0.0},
"valid": false
}
]
},
{
"description": "const with {\"a\": true} does not match {\"a\": 1}",
"schema": {"const": {"a": true}},
"tests": [
{
"description": "{\"a\": true} is valid",
"data": {"a": true},
"valid": true
},
{
"description": "{\"a\": 1} is invalid",
"data": {"a": 1},
"valid": false
},
{
"description": "{\"a\": 1.0} is invalid",
"data": {"a": 1.0},
"valid": false
}
]
},
{
"description": "const with 0 does not match other zero-like types",
"schema": {"const": 0},
"tests": [
{
"description": "false is invalid",
"data": false,
"valid": false
},
{
"description": "integer zero is valid",
"data": 0,
"valid": true
},
{
"description": "float zero is valid",
"data": 0.0,
"valid": true
},
{
"description": "empty object is invalid",
"data": {},
"valid": false
},
{
"description": "empty array is invalid",
"data": [],
"valid": false
},
{
"description": "empty string is invalid",
"data": "",
"valid": false
}
]
},
{
"description": "const with 1 does not match true",
"schema": {"const": 1},
"tests": [
{
"description": "true is invalid",
"data": true,
"valid": false
},
{
"description": "integer one is valid",
"data": 1,
"valid": true
},
{
"description": "float one is valid",
"data": 1.0,
"valid": true
}
]
},
{
"description": "const with -2.0 matches integer and float types",
"schema": {"const": -2.0},
"tests": [
{
"description": "integer -2 is valid",
"data": -2,
"valid": true
},
{
"description": "integer 2 is invalid",
"data": 2,
"valid": false
},
{
"description": "float -2.0 is valid",
"data": -2.0,
"valid": true
},
{
"description": "float 2.0 is invalid",
"data": 2.0,
"valid": false
},
{
"description": "float -2.00001 is invalid",
"data": -2.00001,
"valid": false
}
]
},
{
"description": "float and integers are equal up to 64-bit representation limits",
"schema": {"const": 9007199254740992},
"tests": [
{
"description": "integer is valid",
"data": 9007199254740992,
"valid": true
},
{
"description": "integer minus one is invalid",
"data": 9007199254740991,
"valid": false
},
{
"description": "float is valid",
"data": 9007199254740992.0,
"valid": true
},
{
"description": "float minus one is invalid",
"data": 9007199254740991.0,
"valid": false
}
]
},
{
"description": "nul characters in strings",
"schema": { "const": "hello\u0000there" },
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"valid": true
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"valid": false
}
]
} }
] ]

View File

@ -85,61 +85,6 @@
"data": ["foo"], "data": ["foo"],
"valid": false "valid": false
}, },
{
"description": "empty array is invalid",
"data": [],
"valid": false
},
{
"description": "non-arrays are valid",
"data": "contains does not apply to strings",
"valid": true
}
]
},
{
"description": "items + contains",
"schema": {
"items": { "multipleOf": 2 },
"contains": { "multipleOf": 3 }
},
"tests": [
{
"description": "matches items, does not match contains",
"data": [ 2, 4, 8 ],
"valid": false
},
{
"description": "does not match items, matches contains",
"data": [ 3, 6, 9 ],
"valid": false
},
{
"description": "matches both items and contains",
"data": [ 6, 12 ],
"valid": true
},
{
"description": "matches neither items nor contains",
"data": [ 1, 5 ],
"valid": false
}
]
},
{
"description": "contains with false if subschema",
"schema": {
"contains": {
"if": false,
"else": true
}
},
"tests": [
{
"description": "any non-empty array is valid",
"data": ["foo"],
"valid": true
},
{ {
"description": "empty array is invalid", "description": "empty array is invalid",
"data": [], "data": [],

View File

@ -45,35 +45,5 @@
"valid": true "valid": true
} }
] ]
},
{
"description": "the default keyword does not do anything if the property is missing",
"schema": {
"type": "object",
"properties": {
"alpha": {
"type": "number",
"maximum": 3,
"default": 5
}
}
},
"tests": [
{
"description": "an explicit property value is checked against maximum (passing)",
"data": { "alpha": 1 },
"valid": true
},
{
"description": "an explicit property value is checked against maximum (failing)",
"data": { "alpha": 5 },
"valid": false
},
{
"description": "missing properties are not filled in with the default",
"data": {},
"valid": true
}
]
} }
] ]

View File

@ -1,6 +1,6 @@
[ [
{ {
"description": "validate definition against metaschema", "description": "valid definition",
"schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
"tests": [ "tests": [
{ {
@ -11,7 +11,13 @@
} }
}, },
"valid": true "valid": true
}, }
]
},
{
"description": "invalid definition",
"schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
"tests": [
{ {
"description": "invalid definition schema", "description": "invalid definition schema",
"data": { "data": {

View File

@ -57,11 +57,6 @@
"description": "object with one property", "description": "object with one property",
"data": {"bar": 2}, "data": {"bar": 2},
"valid": true "valid": true
},
{
"description": "non-object is valid",
"data": 1,
"valid": true
} }
] ]
}, },
@ -174,6 +169,31 @@
} }
] ]
}, },
{
"description": "empty array of dependencies",
"schema": {
"dependencies": {
"foo": []
}
},
"tests": [
{
"description": "object with property is valid",
"data": { "foo": 1 },
"valid": true
},
{
"description": "empty object is valid",
"data": {},
"valid": true
},
{
"description": "non-object is valid",
"data": 1,
"valid": true
}
]
},
{ {
"description": "dependencies with escaped characters", "description": "dependencies with escaped characters",
"schema": { "schema": {

View File

@ -33,37 +33,6 @@
"description": "objects are deep compared", "description": "objects are deep compared",
"data": {"foo": false}, "data": {"foo": false},
"valid": false "valid": false
},
{
"description": "valid object matches",
"data": {"foo": 12},
"valid": true
},
{
"description": "extra properties in object is invalid",
"data": {"foo": 12, "boo": 42},
"valid": false
}
]
},
{
"description": "heterogeneous enum-with-null validation",
"schema": { "enum": [6, null] },
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "number is valid",
"data": 6,
"valid": true
},
{
"description": "something else is invalid",
"data": "test",
"valid": false
} }
] ]
}, },
@ -83,16 +52,6 @@
"data": {"foo":"foo", "bar":"bar"}, "data": {"foo":"foo", "bar":"bar"},
"valid": true "valid": true
}, },
{
"description": "wrong foo value",
"data": {"foo":"foot", "bar":"bar"},
"valid": false
},
{
"description": "wrong bar value",
"data": {"foo":"foo", "bar":"bart"},
"valid": false
},
{ {
"description": "missing optional property is valid", "description": "missing optional property is valid",
"data": {"bar":"bar"}, "data": {"bar":"bar"},
@ -132,105 +91,5 @@
"valid": false "valid": false
} }
] ]
},
{
"description": "enum with false does not match 0",
"schema": {"enum": [false]},
"tests": [
{
"description": "false is valid",
"data": false,
"valid": true
},
{
"description": "integer zero is invalid",
"data": 0,
"valid": false
},
{
"description": "float zero is invalid",
"data": 0.0,
"valid": false
}
]
},
{
"description": "enum with true does not match 1",
"schema": {"enum": [true]},
"tests": [
{
"description": "true is valid",
"data": true,
"valid": true
},
{
"description": "integer one is invalid",
"data": 1,
"valid": false
},
{
"description": "float one is invalid",
"data": 1.0,
"valid": false
}
]
},
{
"description": "enum with 0 does not match false",
"schema": {"enum": [0]},
"tests": [
{
"description": "false is invalid",
"data": false,
"valid": false
},
{
"description": "integer zero is valid",
"data": 0,
"valid": true
},
{
"description": "float zero is valid",
"data": 0.0,
"valid": true
}
]
},
{
"description": "enum with 1 does not match true",
"schema": {"enum": [1]},
"tests": [
{
"description": "true is invalid",
"data": true,
"valid": false
},
{
"description": "integer one is valid",
"data": 1,
"valid": true
},
{
"description": "float one is valid",
"data": 1.0,
"valid": true
}
]
},
{
"description": "nul characters in strings",
"schema": { "enum": [ "hello\u0000there" ] },
"tests": [
{
"description": "match string with nul",
"data": "hello\u0000there",
"valid": true
},
{
"description": "do not match string lacking nul",
"data": "hellothere",
"valid": false
}
]
} }
] ]

View File

@ -1,614 +0,0 @@
[
{
"description": "email format",
"schema": { "format": "email" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "idn-email format",
"schema": { "format": "idn-email" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "regex format",
"schema": { "format": "regex" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "ipv4 format",
"schema": { "format": "ipv4" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "ipv6 format",
"schema": { "format": "ipv6" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "idn-hostname format",
"schema": { "format": "idn-hostname" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "hostname format",
"schema": { "format": "hostname" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "date format",
"schema": { "format": "date" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "date-time format",
"schema": { "format": "date-time" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "time format",
"schema": { "format": "time" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "json-pointer format",
"schema": { "format": "json-pointer" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "relative-json-pointer format",
"schema": { "format": "relative-json-pointer" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "iri format",
"schema": { "format": "iri" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "iri-reference format",
"schema": { "format": "iri-reference" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "uri format",
"schema": { "format": "uri" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "uri-reference format",
"schema": { "format": "uri-reference" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
},
{
"description": "uri-template format",
"schema": { "format": "uri-template" },
"tests": [
{
"description": "all string formats ignore integers",
"data": 12,
"valid": true
},
{
"description": "all string formats ignore floats",
"data": 13.7,
"valid": true
},
{
"description": "all string formats ignore objects",
"data": {},
"valid": true
},
{
"description": "all string formats ignore arrays",
"data": [],
"valid": true
},
{
"description": "all string formats ignore booleans",
"data": false,
"valid": true
},
{
"description": "all string formats ignore nulls",
"data": null,
"valid": true
}
]
}
]

View File

@ -1,53 +0,0 @@
[
{
"description": "id inside an enum is not a real identifier",
"comment": "the implementation must not be confused by an id buried in the enum",
"schema": {
"definitions": {
"id_in_enum": {
"enum": [
{
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "null"
}
]
},
"real_id_in_schema": {
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "string"
},
"zzz_id_in_const": {
"const": {
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "null"
}
}
},
"anyOf": [
{ "$ref": "#/definitions/id_in_enum" },
{ "$ref": "https://localhost:1234/id/my_identifier.json" }
]
},
"tests": [
{
"description": "exact match to enum, and type matches",
"data": {
"$id": "https://localhost:1234/id/my_identifier.json",
"type": "null"
},
"valid": true
},
{
"description": "match $ref to id",
"data": "a string to match #/definitions/id_in_enum",
"valid": true
},
{
"description": "no match on enum or $ref to id",
"data": 1,
"valid": false
}
]
}
]

View File

@ -174,7 +174,7 @@
}, },
"tests": [ "tests": [
{ {
"description": "valid, but would have been invalid through then", "description": "valid, but woud have been invalid through then",
"data": -100, "data": -100,
"valid": true "valid": true
}, },
@ -184,75 +184,5 @@
"valid": true "valid": true
} }
] ]
},
{
"description": "if with boolean schema true",
"schema": {
"if": true,
"then": { "const": "then" },
"else": { "const": "else" }
},
"tests": [
{
"description": "boolean schema true in if always chooses the then path (valid)",
"data": "then",
"valid": true
},
{
"description": "boolean schema true in if always chooses the then path (invalid)",
"data": "else",
"valid": false
}
]
},
{
"description": "if with boolean schema false",
"schema": {
"if": false,
"then": { "const": "then" },
"else": { "const": "else" }
},
"tests": [
{
"description": "boolean schema false in if always chooses the else path (invalid)",
"data": "then",
"valid": false
},
{
"description": "boolean schema false in if always chooses the else path (valid)",
"data": "else",
"valid": true
}
]
},
{
"description": "if appears at the end when serialized (keyword processing sequence)",
"schema": {
"then": { "const": "yes" },
"else": { "const": "other" },
"if": { "maxLength": 4 }
},
"tests": [
{
"description": "yes redirects to then and passes",
"data": "yes",
"valid": true
},
{
"description": "other redirects to else and passes",
"data": "other",
"valid": true
},
{
"description": "no redirects to then and fails",
"data": "no",
"valid": false
},
{
"description": "invalid redirects to else and fails",
"data": "invalid",
"valid": false
}
]
} }
] ]

View File

@ -1,36 +0,0 @@
[
{
"description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop",
"schema": {
"definitions": {
"int": { "type": "integer" }
},
"allOf": [
{
"properties": {
"foo": {
"$ref": "#/definitions/int"
}
}
},
{
"additionalProperties": {
"$ref": "#/definitions/int"
}
}
]
},
"tests": [
{
"description": "passing case",
"data": { "foo": 1 },
"valid": true
},
{
"description": "failing case",
"data": { "foo": "a string" },
"valid": false
}
]
}
]

View File

@ -34,21 +34,5 @@
"valid": true "valid": true
} }
] ]
},
{
"description": "maxProperties = 0 means the object is empty",
"schema": { "maxProperties": 0 },
"tests": [
{
"description": "no properties is valid",
"data": {},
"valid": true
},
{
"description": "one property is invalid",
"data": { "foo": 1 },
"valid": false
}
]
} }
] ]

View File

@ -24,31 +24,5 @@
"valid": true "valid": true
} }
] ]
},
{
"description": "maximum validation with unsigned integer",
"schema": {"maximum": 300},
"tests": [
{
"description": "below the maximum is invalid",
"data": 299.97,
"valid": true
},
{
"description": "boundary point integer is valid",
"data": 300,
"valid": true
},
{
"description": "boundary point float is valid",
"data": 300.00,
"valid": true
},
{
"description": "above the maximum is invalid",
"data": 300.5,
"valid": false
}
]
} }
] ]

View File

@ -45,17 +45,7 @@
"valid": true "valid": true
}, },
{ {
"description": "boundary point with float is valid", "description": "below the minimum is invalid",
"data": -2.0,
"valid": true
},
{
"description": "float below the minimum is invalid",
"data": -2.0001,
"valid": false
},
{
"description": "int below the minimum is invalid",
"data": -3, "data": -3,
"valid": false "valid": false
}, },

View File

@ -56,16 +56,5 @@
"valid": false "valid": false
} }
] ]
},
{
"description": "invalid instance should not raise error when float division = inf",
"schema": {"type": "integer", "multipleOf": 0.123456789},
"tests": [
{
"description": "always invalid, but naive implementations may raise an overflow error",
"data": 1e308,
"valid": false
}
]
} }
] ]

View File

@ -74,7 +74,7 @@
"description": "forbidden property", "description": "forbidden property",
"schema": { "schema": {
"properties": { "properties": {
"foo": { "foo": {
"not": {} "not": {}
} }
} }

View File

@ -202,73 +202,5 @@
"valid": false "valid": false
} }
] ]
},
{
"description": "oneOf with missing optional property",
"schema": {
"oneOf": [
{
"properties": {
"bar": true,
"baz": true
},
"required": ["bar"]
},
{
"properties": {
"foo": true
},
"required": ["foo"]
}
]
},
"tests": [
{
"description": "first oneOf valid",
"data": {"bar": 8},
"valid": true
},
{
"description": "second oneOf valid",
"data": {"foo": "foo"},
"valid": true
},
{
"description": "both oneOf valid",
"data": {"foo": "foo", "bar": 8},
"valid": false
},
{
"description": "neither oneOf valid",
"data": {"baz": "quux"},
"valid": false
}
]
},
{
"description": "nested oneOf, to check validation semantics",
"schema": {
"oneOf": [
{
"oneOf": [
{
"type": "null"
}
]
}
]
},
"tests": [
{
"description": "null is valid",
"data": null,
"valid": true
},
{
"description": "anything non-null is invalid",
"data": 123,
"valid": false
}
]
} }
] ]

View File

@ -1,13 +1,30 @@
[ [
{ {
"description": "integer", "description": "integer",
"schema": { "type": "integer" }, "schema": {"type": "integer"},
"tests": [ "tests": [
{ {
"description": "a bignum is an integer", "description": "a bignum is an integer",
"data": 12345678910111213141516171819202122232425262728293031, "data": 12345678910111213141516171819202122232425262728293031,
"valid": true "valid": true
}, }
]
},
{
"description": "number",
"schema": {"type": "number"},
"tests": [
{
"description": "a bignum is a number",
"data": 98249283749234923498293171823948729348710298301928331,
"valid": true
}
]
},
{
"description": "integer",
"schema": {"type": "integer"},
"tests": [
{ {
"description": "a negative bignum is an integer", "description": "a negative bignum is an integer",
"data": -12345678910111213141516171819202122232425262728293031, "data": -12345678910111213141516171819202122232425262728293031,
@ -17,13 +34,8 @@
}, },
{ {
"description": "number", "description": "number",
"schema": { "type": "number" }, "schema": {"type": "number"},
"tests": [ "tests": [
{
"description": "a bignum is a number",
"data": 98249283749234923498293171823948729348710298301928331,
"valid": true
},
{ {
"description": "a negative bignum is a number", "description": "a negative bignum is a number",
"data": -98249283749234923498293171823948729348710298301928331, "data": -98249283749234923498293171823948729348710298301928331,
@ -33,7 +45,7 @@
}, },
{ {
"description": "string", "description": "string",
"schema": { "type": "string" }, "schema": {"type": "string"},
"tests": [ "tests": [
{ {
"description": "a bignum is not a string", "description": "a bignum is not a string",
@ -44,7 +56,7 @@
}, },
{ {
"description": "integer comparison", "description": "integer comparison",
"schema": { "maximum": 18446744073709551615 }, "schema": {"maximum": 18446744073709551615},
"tests": [ "tests": [
{ {
"description": "comparison works for high numbers", "description": "comparison works for high numbers",
@ -68,7 +80,7 @@
}, },
{ {
"description": "integer comparison", "description": "integer comparison",
"schema": { "minimum": -18446744073709551615 }, "schema": {"minimum": -18446744073709551615},
"tests": [ "tests": [
{ {
"description": "comparison works for very negative numbers", "description": "comparison works for very negative numbers",

View File

@ -1,291 +1,12 @@
[ [
{ {
"description": "ECMA 262 regex $ does not match trailing newline", "description": "ECMA 262 regex non-compliance",
"schema": { "schema": { "format": "regex" },
"type": "string",
"pattern": "^abc$"
},
"tests": [ "tests": [
{ {
"description": "matches in Python, but should not in jsonschema", "description": "ECMA 262 has no support for \\Z anchor from .NET",
"data": "abc\\n", "data": "^\\S(|(.|\\n)*\\S)\\Z",
"valid": false "valid": false
},
{
"description": "should match",
"data": "abc",
"valid": true
}
]
},
{
"description": "ECMA 262 regex converts \\t to horizontal tab",
"schema": {
"type": "string",
"pattern": "^\\t$"
},
"tests": [
{
"description": "does not match",
"data": "\\t",
"valid": false
},
{
"description": "matches",
"data": "\u0009",
"valid": true
}
]
},
{
"description": "ECMA 262 regex escapes control codes with \\c and upper letter",
"schema": {
"type": "string",
"pattern": "^\\cC$"
},
"tests": [
{
"description": "does not match",
"data": "\\cC",
"valid": false
},
{
"description": "matches",
"data": "\u0003",
"valid": true
}
]
},
{
"description": "ECMA 262 regex escapes control codes with \\c and lower letter",
"schema": {
"type": "string",
"pattern": "^\\cc$"
},
"tests": [
{
"description": "does not match",
"data": "\\cc",
"valid": false
},
{
"description": "matches",
"data": "\u0003",
"valid": true
}
]
},
{
"description": "ECMA 262 \\d matches ascii digits only",
"schema": {
"type": "string",
"pattern": "^\\d$"
},
"tests": [
{
"description": "ASCII zero matches",
"data": "0",
"valid": true
},
{
"description": "NKO DIGIT ZERO does not match (unlike e.g. Python)",
"data": "߀",
"valid": false
},
{
"description": "NKO DIGIT ZERO (as \\u escape) does not match",
"data": "\u07c0",
"valid": false
}
]
},
{
"description": "ECMA 262 \\D matches everything but ascii digits",
"schema": {
"type": "string",
"pattern": "^\\D$"
},
"tests": [
{
"description": "ASCII zero does not match",
"data": "0",
"valid": false
},
{
"description": "NKO DIGIT ZERO matches (unlike e.g. Python)",
"data": "߀",
"valid": true
},
{
"description": "NKO DIGIT ZERO (as \\u escape) matches",
"data": "\u07c0",
"valid": true
}
]
},
{
"description": "ECMA 262 \\w matches ascii letters only",
"schema": {
"type": "string",
"pattern": "^\\w$"
},
"tests": [
{
"description": "ASCII 'a' matches",
"data": "a",
"valid": true
},
{
"description": "latin-1 e-acute does not match (unlike e.g. Python)",
"data": "é",
"valid": false
}
]
},
{
"description": "ECMA 262 \\W matches everything but ascii letters",
"schema": {
"type": "string",
"pattern": "^\\W$"
},
"tests": [
{
"description": "ASCII 'a' does not match",
"data": "a",
"valid": false
},
{
"description": "latin-1 e-acute matches (unlike e.g. Python)",
"data": "é",
"valid": true
}
]
},
{
"description": "ECMA 262 \\s matches whitespace",
"schema": {
"type": "string",
"pattern": "^\\s$"
},
"tests": [
{
"description": "ASCII space matches",
"data": " ",
"valid": true
},
{
"description": "Character tabulation matches",
"data": "\t",
"valid": true
},
{
"description": "Line tabulation matches",
"data": "\u000b",
"valid": true
},
{
"description": "Form feed matches",
"data": "\u000c",
"valid": true
},
{
"description": "latin-1 non-breaking-space matches",
"data": "\u00a0",
"valid": true
},
{
"description": "zero-width whitespace matches",
"data": "\ufeff",
"valid": true
},
{
"description": "line feed matches (line terminator)",
"data": "\u000a",
"valid": true
},
{
"description": "paragraph separator matches (line terminator)",
"data": "\u2029",
"valid": true
},
{
"description": "EM SPACE matches (Space_Separator)",
"data": "\u2003",
"valid": true
},
{
"description": "Non-whitespace control does not match",
"data": "\u0001",
"valid": false
},
{
"description": "Non-whitespace does not match",
"data": "\u2013",
"valid": false
}
]
},
{
"description": "ECMA 262 \\S matches everything but whitespace",
"schema": {
"type": "string",
"pattern": "^\\S$"
},
"tests": [
{
"description": "ASCII space does not match",
"data": " ",
"valid": false
},
{
"description": "Character tabulation does not match",
"data": "\t",
"valid": false
},
{
"description": "Line tabulation does not match",
"data": "\u000b",
"valid": false
},
{
"description": "Form feed does not match",
"data": "\u000c",
"valid": false
},
{
"description": "latin-1 non-breaking-space does not match",
"data": "\u00a0",
"valid": false
},
{
"description": "zero-width whitespace does not match",
"data": "\ufeff",
"valid": false
},
{
"description": "line feed does not match (line terminator)",
"data": "\u000a",
"valid": false
},
{
"description": "paragraph separator does not match (line terminator)",
"data": "\u2029",
"valid": false
},
{
"description": "EM SPACE does not match (Space_Separator)",
"data": "\u2003",
"valid": false
},
{
"description": "Non-whitespace control matches",
"data": "\u0001",
"valid": true
},
{
"description": "Non-whitespace matches",
"data": "\u2013",
"valid": true
} }
] ]
} }

View File

@ -1,13 +0,0 @@
[
{
"description": "all integers are multiples of 0.5, if overflow is handled",
"schema": {"type": "integer", "multipleOf": 0.5},
"tests": [
{
"description": "valid if optional overflow handling is implemented",
"data": 1e308,
"valid": true
}
]
}
]

View File

@ -47,26 +47,6 @@
"description": "only RFC3339 not all of ISO 8601 are valid", "description": "only RFC3339 not all of ISO 8601 are valid",
"data": "2013-350T01:01:01", "data": "2013-350T01:01:01",
"valid": false "valid": false
},
{
"description": "invalid non-padded month dates",
"data": "1963-6-19T08:30:06.283185Z",
"valid": false
},
{
"description": "invalid non-padded day dates",
"data": "1963-06-1T08:30:06.283185Z",
"valid": false
},
{
"description": "non-ascii digits should be rejected in the date portion",
"data": "1963-06-1T00:00:00Z",
"valid": false
},
{
"description": "non-ascii digits should be rejected in the time portion",
"data": "1963-06-11T0:00:00Z",
"valid": false
} }
] ]
} }

View File

@ -9,142 +9,7 @@
"valid": true "valid": true
}, },
{ {
"description": "a valid date string with 31 days in January", "description": "an invalid date-time string",
"data": "2020-01-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in January",
"data": "2020-01-32",
"valid": false
},
{
"description": "a valid date string with 28 days in February (normal)",
"data": "2021-02-28",
"valid": true
},
{
"description": "a invalid date string with 29 days in February (normal)",
"data": "2021-02-29",
"valid": false
},
{
"description": "a valid date string with 29 days in February (leap)",
"data": "2020-02-29",
"valid": true
},
{
"description": "a invalid date string with 30 days in February (leap)",
"data": "2020-02-30",
"valid": false
},
{
"description": "a valid date string with 31 days in March",
"data": "2020-03-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in March",
"data": "2020-03-32",
"valid": false
},
{
"description": "a valid date string with 30 days in April",
"data": "2020-04-30",
"valid": true
},
{
"description": "a invalid date string with 31 days in April",
"data": "2020-04-31",
"valid": false
},
{
"description": "a valid date string with 31 days in May",
"data": "2020-05-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in May",
"data": "2020-05-32",
"valid": false
},
{
"description": "a valid date string with 30 days in June",
"data": "2020-06-30",
"valid": true
},
{
"description": "a invalid date string with 31 days in June",
"data": "2020-06-31",
"valid": false
},
{
"description": "a valid date string with 31 days in July",
"data": "2020-07-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in July",
"data": "2020-07-32",
"valid": false
},
{
"description": "a valid date string with 31 days in August",
"data": "2020-08-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in August",
"data": "2020-08-32",
"valid": false
},
{
"description": "a valid date string with 30 days in September",
"data": "2020-09-30",
"valid": true
},
{
"description": "a invalid date string with 31 days in September",
"data": "2020-09-31",
"valid": false
},
{
"description": "a valid date string with 31 days in October",
"data": "2020-10-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in October",
"data": "2020-10-32",
"valid": false
},
{
"description": "a valid date string with 30 days in November",
"data": "2020-11-30",
"valid": true
},
{
"description": "a invalid date string with 31 days in November",
"data": "2020-11-31",
"valid": false
},
{
"description": "a valid date string with 31 days in December",
"data": "2020-12-31",
"valid": true
},
{
"description": "a invalid date string with 32 days in December",
"data": "2020-12-32",
"valid": false
},
{
"description": "a invalid date string with invalid month",
"data": "2020-13-01",
"valid": false
},
{
"description": "an invalid date string",
"data": "06/19/1963", "data": "06/19/1963",
"valid": false "valid": false
}, },
@ -152,41 +17,6 @@
"description": "only RFC3339 not all of ISO 8601 are valid", "description": "only RFC3339 not all of ISO 8601 are valid",
"data": "2013-350", "data": "2013-350",
"valid": false "valid": false
},
{
"description": "non-padded month dates are not valid",
"data": "1998-1-20",
"valid": false
},
{
"description": "non-padded day dates are not valid",
"data": "1998-01-1",
"valid": false
},
{
"description": "invalid month",
"data": "1998-13-01",
"valid": false
},
{
"description": "invalid month-day combination",
"data": "1998-04-31",
"valid": false
},
{
"description": "2021 is not a leap year",
"data": "2021-02-29",
"valid": false
},
{
"description": "2020 is a leap year",
"data": "2020-02-29",
"valid": true
},
{
"description": "non-ascii digits should be rejected",
"data": "1963-06-1",
"valid": false
} }
] ]
} }

View File

@ -12,41 +12,6 @@
"description": "an invalid e-mail address", "description": "an invalid e-mail address",
"data": "2962", "data": "2962",
"valid": false "valid": false
},
{
"description": "tilde in local part is valid",
"data": "te~st@example.com",
"valid": true
},
{
"description": "tilde before local part is valid",
"data": "~test@example.com",
"valid": true
},
{
"description": "tilde after local part is valid",
"data": "test~@example.com",
"valid": true
},
{
"description": "dot before local part is not valid",
"data": ".test@example.com",
"valid": false
},
{
"description": "dot after local part is not valid",
"data": "test.@example.com",
"valid": false
},
{
"description": "two separated dots inside local part are valid",
"data": "te.s.t@example.com",
"valid": true
},
{
"description": "two subsequent dots inside local part are not valid",
"data": "te..st@example.com",
"valid": false
} }
] ]
} }

View File

@ -27,41 +27,6 @@
"description": "a host name with a component too long", "description": "a host name with a component too long",
"data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component", "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component",
"valid": false "valid": false
},
{
"description": "starts with hyphen",
"data": "-hostname",
"valid": false
},
{
"description": "ends with hyphen",
"data": "hostname-",
"valid": false
},
{
"description": "starts with underscore",
"data": "_hostname",
"valid": false
},
{
"description": "ends with underscore",
"data": "hostname_",
"valid": false
},
{
"description": "contains underscore",
"data": "host_name",
"valid": false
},
{
"description": "maximum label length",
"data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com",
"valid": true
},
{
"description": "exceeds maximum label length",
"data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com",
"valid": false
} }
] ]
} }

View File

@ -12,16 +12,6 @@
"description": "an invalid idn e-mail address", "description": "an invalid idn e-mail address",
"data": "2962", "data": "2962",
"valid": false "valid": false
},
{
"description": "a valid e-mail address",
"data": "joe.bloggs@example.com",
"valid": true
},
{
"description": "an invalid e-mail address",
"data": "2962",
"valid": false
} }
] ]
} }

View File

@ -22,252 +22,6 @@
"description": "a host name with a component too long", "description": "a host name with a component too long",
"data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트",
"valid": false "valid": false
},
{
"description": "invalid label, correct Punycode",
"comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1",
"data": "-> $1.00 <--",
"valid": false
},
{
"description": "valid Chinese Punycode",
"comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4",
"data": "xn--ihqwcrb4cv8a8dqg056pqjye",
"valid": true
},
{
"description": "invalid Punycode",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1",
"data": "xn--X",
"valid": false
},
{
"description": "U-label contains \"--\" in the 3rd and 4th position",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1",
"data": "XN--aa---o47jg78q",
"valid": false
},
{
"description": "U-label starts with a dash",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1",
"data": "-hello",
"valid": false
},
{
"description": "U-label ends with a dash",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1",
"data": "hello-",
"valid": false
},
{
"description": "U-label starts and ends with a dash",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1",
"data": "-hello-",
"valid": false
},
{
"description": "Begins with a Spacing Combining Mark",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2",
"data": "\u0903hello",
"valid": false
},
{
"description": "Begins with a Nonspacing Mark",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2",
"data": "\u0300hello",
"valid": false
},
{
"description": "Begins with an Enclosing Mark",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2",
"data": "\u0488hello",
"valid": false
},
{
"description": "Exceptions that are PVALID, left-to-right chars",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6",
"data": "\u00df\u03c2\u0f0b\u3007",
"valid": true
},
{
"description": "Exceptions that are PVALID, right-to-left chars",
"comment": "https://tools.ietf.org/html/rfc/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6",
"data": "\u06fd\u06fe",
"valid": true
},
{
"description": "Exceptions that are DISALLOWED, right-to-left chars",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6",
"data": "\u0640\u07fa",
"valid": false
},
{
"description": "Exceptions that are DISALLOWED, left-to-right chars",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start",
"data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b",
"valid": false
},
{
"description": "MIDDLE DOT with no preceding 'l'",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
"data": "a\u00b7l",
"valid": false
},
{
"description": "MIDDLE DOT with nothing preceding",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
"data": "\u00b7l",
"valid": false
},
{
"description": "MIDDLE DOT with no following 'l'",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
"data": "l\u00b7a",
"valid": false
},
{
"description": "MIDDLE DOT with nothing following",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
"data": "l\u00b7",
"valid": false
},
{
"description": "MIDDLE DOT with surrounding 'l's",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
"data": "l\u00b7l",
"valid": true
},
{
"description": "Greek KERAIA not followed by Greek",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4",
"data": "\u03b1\u0375S",
"valid": false
},
{
"description": "Greek KERAIA not followed by anything",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4",
"data": "\u03b1\u0375",
"valid": false
},
{
"description": "Greek KERAIA followed by Greek",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4",
"data": "\u03b1\u0375\u03b2",
"valid": true
},
{
"description": "Hebrew GERESH not preceded by Hebrew",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5",
"data": "A\u05f3\u05d1",
"valid": false
},
{
"description": "Hebrew GERESH not preceded by anything",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5",
"data": "\u05f3\u05d1",
"valid": false
},
{
"description": "Hebrew GERESH preceded by Hebrew",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5",
"data": "\u05d0\u05f3\u05d1",
"valid": true
},
{
"description": "Hebrew GERSHAYIM not preceded by Hebrew",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6",
"data": "A\u05f4\u05d1",
"valid": false
},
{
"description": "Hebrew GERSHAYIM not preceded by anything",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6",
"data": "\u05f4\u05d1",
"valid": false
},
{
"description": "Hebrew GERSHAYIM preceded by Hebrew",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6",
"data": "\u05d0\u05f4\u05d1",
"valid": true
},
{
"description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
"data": "def\u30fbabc",
"valid": false
},
{
"description": "KATAKANA MIDDLE DOT with no other characters",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
"data": "\u30fb",
"valid": false
},
{
"description": "KATAKANA MIDDLE DOT with Hiragana",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
"data": "\u30fb\u3041",
"valid": true
},
{
"description": "KATAKANA MIDDLE DOT with Katakana",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
"data": "\u30fb\u30a1",
"valid": true
},
{
"description": "KATAKANA MIDDLE DOT with Han",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
"data": "\u30fb\u4e08",
"valid": true
},
{
"description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8",
"data": "\u0660\u06f0",
"valid": false
},
{
"description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8",
"data": "\u0628\u0660\u0628",
"valid": true
},
{
"description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9",
"data": "\u06f00",
"valid": true
},
{
"description": "ZERO WIDTH JOINER not preceded by Virama",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf",
"data": "\u0915\u200d\u0937",
"valid": false
},
{
"description": "ZERO WIDTH JOINER not preceded by anything",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf",
"data": "\u200d\u0937",
"valid": false
},
{
"description": "ZERO WIDTH JOINER preceded by Virama",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf",
"data": "\u0915\u094d\u200d\u0937",
"valid": true
},
{
"description": "ZERO WIDTH NON-JOINER preceded by Virama",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1",
"data": "\u0915\u094d\u200c\u0937",
"valid": true
},
{
"description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp",
"comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement",
"data": "\u0628\u064a\u200c\u0628\u064a",
"valid": true
} }
] ]
} }

View File

@ -27,27 +27,6 @@
"description": "an IP address as an integer", "description": "an IP address as an integer",
"data": "0x7f000001", "data": "0x7f000001",
"valid": false "valid": false
},
{
"description": "an IP address as an integer (decimal)",
"data": "2130706433",
"valid": false
},
{
"description": "leading zeroes should be rejected, as they are treated as octals",
"comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/",
"data": "087.10.0.1",
"valid": false
},
{
"description": "value without leading zero is valid",
"data": "87.10.0.1",
"valid": true
},
{
"description": "non-ascii digits should be rejected",
"data": "1২7.0.0.1",
"valid": false
} }
] ]
} }

View File

@ -22,141 +22,6 @@
"description": "an IPv6 address containing illegal characters", "description": "an IPv6 address containing illegal characters",
"data": "::laptop", "data": "::laptop",
"valid": false "valid": false
},
{
"description": "no digits is valid",
"data": "::",
"valid": true
},
{
"description": "leading colons is valid",
"data": "::42:ff:1",
"valid": true
},
{
"description": "trailing colons is valid",
"data": "d6::",
"valid": true
},
{
"description": "missing leading octet is invalid",
"data": ":2:3:4:5:6:7:8",
"valid": false
},
{
"description": "missing trailing octet is invalid",
"data": "1:2:3:4:5:6:7:",
"valid": false
},
{
"description": "missing leading octet with omitted octets later",
"data": ":2:3:4::8",
"valid": false
},
{
"description": "two sets of double colons is invalid",
"data": "1::d6::42",
"valid": false
},
{
"description": "mixed format with the ipv4 section as decimal octets",
"data": "1::d6:192.168.0.1",
"valid": true
},
{
"description": "mixed format with double colons between the sections",
"data": "1:2::192.168.0.1",
"valid": true
},
{
"description": "mixed format with ipv4 section with octet out of range",
"data": "1::2:192.168.256.1",
"valid": false
},
{
"description": "mixed format with ipv4 section with a hex octet",
"data": "1::2:192.168.ff.1",
"valid": false
},
{
"description": "mixed format with leading double colons (ipv4-mapped ipv6 address)",
"data": "::ffff:192.168.0.1",
"valid": true
},
{
"description": "triple colons is invalid",
"data": "1:2:3:4:5:::8",
"valid": false
},
{
"description": "8 octets",
"data": "1:2:3:4:5:6:7:8",
"valid": true
},
{
"description": "insufficient octets without double colons",
"data": "1:2:3:4:5:6:7",
"valid": false
},
{
"description": "no colons is invalid",
"data": "1",
"valid": false
},
{
"description": "ipv4 is not ipv6",
"data": "127.0.0.1",
"valid": false
},
{
"description": "ipv4 segment must have 4 octets",
"data": "1:2:3:4:1.2.3",
"valid": false
},
{
"description": "leading whitespace is invalid",
"data": " ::1",
"valid": false
},
{
"description": "trailing whitespace is invalid",
"data": "::1 ",
"valid": false
},
{
"description": "netmask is not a part of ipv6 address",
"data": "fe80::/64",
"valid": false
},
{
"description": "zone id is not a part of ipv6 address",
"data": "fe80::a%eth1",
"valid": false
},
{
"description": "a long valid ipv6",
"data": "1000:1000:1000:1000:1000:1000:255.255.255.255",
"valid": true
},
{
"description": "a long invalid ipv6, below length limit, first",
"data": "100:100:100:100:100:100:255.255.255.255.255",
"valid": false
},
{
"description": "a long invalid ipv6, below length limit, second",
"data": "100:100:100:100:100:100:100:255.255.255.255",
"valid": false
},
{
"description": "non-ascii digits should be rejected",
"data": "1:2:3:4:5:6:7:",
"valid": false
},
{
"description": "non-ascii digits should be rejected in the ipv4 portion also",
"data": "1:2::192.16.0.1",
"valid": false
} }
] ]
} }

View File

@ -9,7 +9,7 @@
"valid": true "valid": true
}, },
{ {
"description": "a valid IRI with anchor tag and parentheses", "description": "a valid IRI with anchor tag and parantheses",
"data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1", "data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1",
"valid": true "valid": true
}, },

View File

@ -9,7 +9,7 @@
"valid": true "valid": true
}, },
{ {
"description": "a valid downwards RJP", "description": "a valid downwards RJP",
"data": "0/foo/bar", "data": "0/foo/bar",
"valid": true "valid": true
}, },
@ -27,26 +27,6 @@
"description": "an invalid RJP that is a valid JSON Pointer", "description": "an invalid RJP that is a valid JSON Pointer",
"data": "/foo/bar", "data": "/foo/bar",
"valid": false "valid": false
},
{
"description": "negative prefix",
"data": "-1/foo/bar",
"valid": false
},
{
"description": "## is not a valid json-pointer",
"data": "0##",
"valid": false
},
{
"description": "zero cannot be followed by other digits, plus json-pointer",
"data": "01/a",
"valid": false
},
{
"description": "zero cannot be followed by other digits, plus octothorpe",
"data": "01#",
"valid": false
} }
] ]
} }

View File

@ -5,146 +5,11 @@
"tests": [ "tests": [
{ {
"description": "a valid time string", "description": "a valid time string",
"data": "08:30:06Z",
"valid": true
},
{
"description": "a valid time string with leap second, Zulu",
"data": "23:59:60Z",
"valid": true
},
{
"description": "invalid leap second, Zulu (wrong hour)",
"data": "22:59:60Z",
"valid": false
},
{
"description": "invalid leap second, Zulu (wrong minute)",
"data": "23:58:60Z",
"valid": false
},
{
"description": "valid leap second, zero time-offset",
"data": "23:59:60+00:00",
"valid": true
},
{
"description": "invalid leap second, zero time-offset (wrong hour)",
"data": "22:59:60+00:00",
"valid": false
},
{
"description": "invalid leap second, zero time-offset (wrong minute)",
"data": "23:58:60+00:00",
"valid": false
},
{
"description": "valid leap second, positive time-offset",
"data": "01:29:60+01:30",
"valid": true
},
{
"description": "valid leap second, large positive time-offset",
"data": "23:29:60+23:30",
"valid": true
},
{
"description": "invalid leap second, positive time-offset (wrong hour)",
"data": "23:59:60+01:00",
"valid": false
},
{
"description": "invalid leap second, positive time-offset (wrong minute)",
"data": "23:59:60+00:30",
"valid": false
},
{
"description": "valid leap second, negative time-offset",
"data": "15:59:60-08:00",
"valid": true
},
{
"description": "valid leap second, large negative time-offset",
"data": "00:29:60-23:30",
"valid": true
},
{
"description": "invalid leap second, negative time-offset (wrong hour)",
"data": "23:59:60-01:00",
"valid": false
},
{
"description": "invalid leap second, negative time-offset (wrong minute)",
"data": "23:59:60-00:30",
"valid": false
},
{
"description": "a valid time string with second fraction",
"data": "23:20:50.52Z",
"valid": true
},
{
"description": "a valid time string with precise second fraction",
"data": "08:30:06.283185Z", "data": "08:30:06.283185Z",
"valid": true "valid": true
}, },
{ {
"description": "a valid time string with plus offset", "description": "an invalid time string",
"data": "08:30:06+00:20",
"valid": true
},
{
"description": "a valid time string with minus offset",
"data": "08:30:06-08:00",
"valid": true
},
{
"description": "a valid time string with case-insensitive Z",
"data": "08:30:06z",
"valid": true
},
{
"description": "an invalid time string with invalid hour",
"data": "24:00:00Z",
"valid": false
},
{
"description": "an invalid time string with invalid minute",
"data": "00:60:00Z",
"valid": false
},
{
"description": "an invalid time string with invalid second",
"data": "00:00:61Z",
"valid": false
},
{
"description": "an invalid time string with invalid leap second (wrong hour)",
"data": "22:59:60Z",
"valid": false
},
{
"description": "an invalid time string with invalid leap second (wrong minute)",
"data": "23:58:60Z",
"valid": false
},
{
"description": "an invalid time string with invalid time numoffset hour",
"data": "01:02:03+24:00",
"valid": false
},
{
"description": "an invalid time string with invalid time numoffset minute",
"data": "01:02:03+00:60",
"valid": false
},
{
"description": "an invalid time string with invalid time with both Z and numoffset",
"data": "01:02:03Z+00:30",
"valid": false
},
{
"description": "an invalid offset indicator",
"data": "08:30:06 PST", "data": "08:30:06 PST",
"valid": false "valid": false
}, },
@ -152,16 +17,6 @@
"description": "only RFC3339 not all of ISO 8601 are valid", "description": "only RFC3339 not all of ISO 8601 are valid",
"data": "01:01:01,1111", "data": "01:01:01,1111",
"valid": false "valid": false
},
{
"description": "no time offset",
"data": "12:00:00",
"valid": false
},
{
"description": "non-ascii digits should be rejected",
"data": "1২:00:00Z",
"valid": false
} }
] ]
} }

View File

@ -1,7 +1,9 @@
[ [
{ {
"description": "format: uri-template", "description": "format: uri-template",
"schema": {"format": "uri-template"}, "schema": {
"format": "uri-template"
},
"tests": [ "tests": [
{ {
"description": "a valid uri-template", "description": "a valid uri-template",

View File

@ -9,7 +9,7 @@
"valid": true "valid": true
}, },
{ {
"description": "a valid URL with anchor tag and parentheses", "description": "a valid URL with anchor tag and parantheses",
"data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1",
"valid": true "valid": true
}, },
@ -97,11 +97,6 @@
"description": "an invalid URI with spaces and missing scheme", "description": "an invalid URI with spaces and missing scheme",
"data": ":// should fail", "data": ":// should fail",
"valid": false "valid": false
},
{
"description": "an invalid URI with comma in scheme",
"data": "bar,baz:foo",
"valid": false
} }
] ]
} }

View File

@ -1,85 +0,0 @@
[
{
"description": "uuid format",
"schema": {
"format": "uuid"
},
"tests": [
{
"description": "all upper-case",
"data": "2EB8AA08-AA98-11EA-B4AA-73B441D16380",
"valid": true
},
{
"description": "all lower-case",
"data": "2eb8aa08-aa98-11ea-b4aa-73b441d16380",
"valid": true
},
{
"description": "mixed case",
"data": "2eb8aa08-AA98-11ea-B4Aa-73B441D16380",
"valid": true
},
{
"description": "all zeroes is valid",
"data": "00000000-0000-0000-0000-000000000000",
"valid": true
},
{
"description": "wrong length",
"data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638",
"valid": false
},
{
"description": "missing section",
"data": "2eb8aa08-aa98-11ea-73b441d16380",
"valid": false
},
{
"description": "bad characters (not hex)",
"data": "2eb8aa08-aa98-11ea-b4ga-73b441d16380",
"valid": false
},
{
"description": "no dashes",
"data": "2eb8aa08aa9811eab4aa73b441d16380",
"valid": false
},
{
"description": "too few dashes",
"data": "2eb8aa08aa98-11ea-b4aa73b441d16380",
"valid": false
},
{
"description": "too many dashes",
"data": "2eb8-aa08-aa98-11ea-b4aa73b44-1d16380",
"valid": false
},
{
"description": "dashes in the wrong spot",
"data": "2eb8aa08aa9811eab4aa73b441d16380----",
"valid": false
},
{
"description": "valid version 4",
"data": "98d80576-482e-427f-8434-7f86890ab222",
"valid": true
},
{
"description": "valid version 5",
"data": "99c17cbb-656f-564a-940f-1a4568f03487",
"valid": true
},
{
"description": "hypothetical version 6",
"data": "99c17cbb-656f-664a-940f-1a4568f03487",
"valid": true
},
{
"description": "hypothetical version 15",
"data": "99c17cbb-656f-f64a-940f-1a4568f03487",
"valid": true
}
]
}
]

View File

@ -1,82 +0,0 @@
[
{
"description": "Proper UTF-16 surrogate pair handling: pattern",
"comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters",
"schema": { "pattern": "^🐲*$" },
"tests": [
{
"description": "matches empty",
"data": "",
"valid": true
},
{
"description": "matches single",
"data": "🐲",
"valid": true
},
{
"description": "matches two",
"data": "🐲🐲",
"valid": true
},
{
"description": "doesn't match one",
"data": "🐉",
"valid": false
},
{
"description": "doesn't match two",
"data": "🐉🐉",
"valid": false
},
{
"description": "doesn't match one ASCII",
"data": "D",
"valid": false
},
{
"description": "doesn't match two ASCII",
"data": "DD",
"valid": false
}
]
},
{
"description": "Proper UTF-16 surrogate pair handling: patternProperties",
"comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters",
"schema": {
"patternProperties": {
"^🐲*$": {
"type": "integer"
}
}
},
"tests": [
{
"description": "matches empty",
"data": { "": 1 },
"valid": true
},
{
"description": "matches single",
"data": { "🐲": 1 },
"valid": true
},
{
"description": "matches two",
"data": { "🐲🐲": 1 },
"valid": true
},
{
"description": "doesn't match one",
"data": { "🐲": "hello" },
"valid": false
},
{
"description": "doesn't match two",
"data": { "🐲🐲": "hello" },
"valid": false
}
]
}
]

View File

@ -1,146 +0,0 @@
[
{
"description": "unicode semantics should be used for all pattern matching",
"schema": { "pattern": "\\wcole" },
"tests": [
{
"description": "literal unicode character in json string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": true
},
{
"description": "unicode character in hex format in string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": true
},
{
"description": "unicode matching is case-sensitive",
"data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.",
"valid": false
}
]
},
{
"description": "unicode characters do not match ascii ranges",
"schema": { "pattern": "[a-z]cole" },
"tests": [
{
"description": "literal unicode character in json string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": false
},
{
"description": "unicode character in hex format in string",
"data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
"valid": false
},
{
"description": "ascii characters match",
"data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
"valid": true
}
]
},
{
"description": "unicode digits are more than 0 through 9",
"schema": { "pattern": "^\\d+$" },
"tests": [
{
"description": "ascii digits",
"data": "42",
"valid": true
},
{
"description": "ascii non-digits",
"data": "-%#",
"valid": false
},
{
"description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
"data": "৪২",
"valid": true
}
]
},
{
"description": "unicode semantics should be used for all patternProperties matching",
"schema": {
"type": "object",
"patternProperties": {
"\\wcole": true
},
"additionalProperties": false
},
"tests": [
{
"description": "literal unicode character in json string",
"data": { "l'école": "pas de vraie vie" },
"valid": true
},
{
"description": "unicode character in hex format in string",
"data": { "l'\u00e9cole": "pas de vraie vie" },
"valid": true
},
{
"description": "unicode matching is case-sensitive",
"data": { "L'ÉCOLE": "PAS DE VRAIE VIE" },
"valid": false
}
]
},
{
"description": "unicode characters do not match ascii ranges",
"schema": {
"type": "object",
"patternProperties": {
"[a-z]cole": true
},
"additionalProperties": false
},
"tests": [
{
"description": "literal unicode character in json string",
"data": { "l'école": "pas de vraie vie" },
"valid": false
},
{
"description": "unicode character in hex format in string",
"data": { "l'\u00e9cole": "pas de vraie vie" },
"valid": false
},
{
"description": "ascii characters match",
"data": { "l'ecole": "pas de vraie vie" },
"valid": true
}
]
},
{
"description": "unicode digits are more than 0 through 9",
"schema": {
"type": "object",
"patternProperties": {
"^\\d+$": true
},
"additionalProperties": false
},
"tests": [
{
"description": "ascii digits",
"data": { "42": "life, the universe, and everything" },
"valid": true
},
{
"description": "ascii non-digits",
"data": { "-%#": "spending the year dead for tax reasons" },
"valid": false
},
{
"description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
"data": { "৪২": "khajit has wares if you have coin" },
"valid": true
}
]
}
]

View File

@ -0,0 +1,15 @@
[
{
"description": "some languages do not distinguish between different types of numeric value",
"schema": {
"type": "integer"
},
"tests": [
{
"description": "a float without fractional part is an integer",
"data": 1.0,
"valid": true
}
]
}
]

View File

@ -14,34 +14,9 @@
"valid": false "valid": false
}, },
{ {
"description": "ignores booleans", "description": "ignores non-strings",
"data": true, "data": true,
"valid": true "valid": true
},
{
"description": "ignores integers",
"data": 123,
"valid": true
},
{
"description": "ignores floats",
"data": 1.0,
"valid": true
},
{
"description": "ignores objects",
"data": {},
"valid": true
},
{
"description": "ignores arrays",
"data": [],
"valid": true
},
{
"description": "ignores null",
"data": null,
"valid": true
} }
] ]
}, },

View File

@ -141,11 +141,6 @@
"data": {"foo": 1, "bar": 2}, "data": {"foo": 1, "bar": 2},
"valid": false "valid": false
}, },
{
"description": "object with a property matching both true and false is invalid",
"data": {"foobar":1},
"valid": false
},
{ {
"description": "empty object is valid", "description": "empty object is valid",
"data": {}, "data": {},

View File

@ -43,35 +43,6 @@
} }
] ]
}, },
{
"description": "propertyNames validation with pattern",
"schema": {
"propertyNames": { "pattern": "^a+$" }
},
"tests": [
{
"description": "matching property names valid",
"data": {
"a": {},
"aa": {},
"aaa": {}
},
"valid": true
},
{
"description": "non-matching property name is invalid",
"data": {
"aaA": {}
},
"valid": false
},
{
"description": "object without properties is valid",
"data": {},
"valid": true
}
]
},
{ {
"description": "propertyNames with boolean schema true", "description": "propertyNames with boolean schema true",
"schema": {"propertyNames": true}, "schema": {"propertyNames": true},

Some files were not shown because too many files have changed in this diff Show More