Merge branch 'develop' into coverity_scan

This commit is contained in:
Niels 2016-08-21 23:20:05 +02:00
commit 8fbf635dd3
41 changed files with 16160 additions and 14567 deletions

View File

@ -6,6 +6,10 @@ This project started as a little excuse to exercise some of the cool new C++11 f
To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it! To make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it!
## Private reports
Usually, all issues are tracked publicly on [Github](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be publisheed), please send an email to <mail@nlohmann.me>.
## Prerequisites ## Prerequisites
Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this. Please [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this.
@ -57,6 +61,7 @@ Please understand that I cannot accept pull requests changing only file `src/jso
## Note ## Note
- If you open a pull request, the code will be automatically tested with [Valgrind](http://valgrind.org)'s Memcheck tool to detect memory leaks. Please be aware that the execution with Valgrind _may_ in rare cases yield different behavior than running the code directly. This can result in failing unit tests which run successfully without Valgrind. - If you open a pull request, the code will be automatically tested with [Valgrind](http://valgrind.org)'s Memcheck tool to detect memory leaks. Please be aware that the execution with Valgrind _may_ in rare cases yield different behavior than running the code directly. This can result in failing unit tests which run successfully without Valgrind.
- There is a Makefile target `make pretty` which runs [Artistic Style](http://astyle.sourceforge.net) to fix indentation. If possible, run it before opening the pull request. Otherwise, we shall run it afterward.
## Please don't ## Please don't

10
.gitignore vendored
View File

@ -1,16 +1,16 @@
json_unit json_unit
json_benchmarks json_benchmarks
fuzz-testing fuzz-testing
*.dSYM *.dSYM
*.o
*.gcno
*.gcda
working working
html doc/xml
doc/html
me.nlohmann.json.docset me.nlohmann.json.docset
android
doc/xml
benchmarks/files/numbers/*.json benchmarks/files/numbers/*.json

View File

@ -1,33 +1,87 @@
#########################
# project configuration #
#########################
# C++ project
language: cpp language: cpp
dist: trusty dist: trusty
sudo: required sudo: required
###################
# global settings #
###################
env: env:
global: global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key # via the "travis encrypt" command using the project repo's public key
- secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA=" - secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA="
# from http://stackoverflow.com/a/32127147/266378
################
# build matrix #
################
matrix: matrix:
include: include:
# Valgrind
- os: linux
compiler: gcc
env:
- COMPILER=g++-4.9
- SPECIAL=valgrind
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: [g++-4.9, valgrind]
after_success:
- valgrind --error-exitcode=1 --leak-check=full test/json_unit
# cppcheck
- os: linux
compiler: gcc
env:
- COMPILER=g++-4.9
- SPECIAL=cppcheck
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: [g++-4.9, cppcheck]
after_success:
- make cppcheck
# Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)
- os: linux - os: linux
compiler: gcc compiler: gcc
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-4.9', 'valgrind', 'python-pip', 'python-yaml'] packages: ['g++-4.9', 'ruby']
before_script: before_script:
- pip install --user git+git://github.com/eddyxu/cpp-coveralls.git - wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz
- tar xf lcov_1.11.orig.tar.gz
- sudo make -C lcov-1.11/ install
- gem install coveralls-lcov
after_success: after_success:
- make clean - make clean
- touch src/json.hpp - CXXFLAGS="--coverage -g -O0" CPPFLAGS="-DNDEBUG" make
- make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage -std=c++11 -lstdc++" CXX=$COMPILER - test/json_unit "*"
- ./json_unit "*" - coveralls --build-root test --exclude src/catch.hpp --exclude src/unit-algorithms.cpp --exclude src/unit-allocator.cpp --exclude src/unit-capacity.cpp --exclude src/unit-class_const_iterator.cpp --exclude src/unit-class_iterator.cpp --exclude src/unit-class_lexer.cpp --exclude src/unit-class_parser.cpp --exclude src/unit-comparison.cpp --exclude src/unit-concepts.cpp --exclude src/unit-constructor1.cpp --exclude src/unit-constructor2.cpp --exclude src/unit-convenience.cpp --exclude src/unit-conversions.cpp --exclude src/unit-deserialization.cpp --exclude src/unit-element_access1.cpp --exclude src/unit-element_access2.cpp --exclude src/unit-inspection.cpp --exclude src/unit-iterator_wrapper.cpp --exclude src/unit-iterators1.cpp --exclude src/unit-iterators2.cpp --exclude src/unit-json_patch.cpp --exclude src/unit-json_pointer.cpp --exclude src/unit-modifiers.cpp --exclude src/unit-pointer_access.cpp --exclude src/unit-readme.cpp --exclude src/unit-reference_access.cpp --exclude src/unit-regression.cpp --exclude src/unit-serialization.cpp --exclude src/unit-testsuites.cpp --exclude src/unit-unicode.cpp --include ../src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9'
- coveralls --exclude test/src/catch.hpp --exclude test/src/unit.cpp --include src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9' - lcov --directory src --directory test/src --capture --output-file coverage.info --rc lcov_branch_coverage=1 --no-external
- bash <(curl -s https://codecov.io/bash) - lcov --remove coverage.info 'test/src/*' --output-file coverage.info --rc lcov_branch_coverage=1
env: COMPILER=g++-4.9 - lcov --list coverage.info --rc lcov_branch_coverage=1
- coveralls-lcov --repo-token F9bs4Nop10JRgqPQXRcifyQKYhb3FczkS coverage.info
env:
- COMPILER=g++-4.9
- SPECIAL=coveralls
# Coverity (only for branch coverity_scan)
- os: linux - os: linux
compiler: gcc compiler: gcc
@ -44,133 +98,207 @@ matrix:
build_command_prepend: "make clean ; sudo cp $(which g++-5) $(which g++)" build_command_prepend: "make clean ; sudo cp $(which g++-5) $(which g++)"
build_command: "make" build_command: "make"
branch_pattern: coverity_scan branch_pattern: coverity_scan
env: COMPILER=g++-5
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-6', 'valgrind']
env: COMPILER=g++-6
# from https://github.com/travis-ci/travis-ci/issues/6120
- os: linux
env: env:
- LLVM_VERSION=3.8.0 - COMPILER=g++-5
- LLVM_ARCHIVE_PATH=$HOME/clang+llvm.tar.xz - SPECIAL=coverity
- COMPILER=clang++
- CPPFLAGS="-I $HOME/clang-$LLVM_VERSION/include/c++/v1"
- CXXFLAGS=-lc++
- PATH=$HOME/clang-$LLVM_VERSION/bin:$PATH
- LD_LIBRARY_PATH=$HOME/clang-$LLVM_VERSION/lib:$LD_LIBRARY_PATH
before_install:
- wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-14.04.tar.xz -O $LLVM_ARCHIVE_PATH
- mkdir $HOME/clang-$LLVM_VERSION
- tar xf $LLVM_ARCHIVE_PATH -C $HOME/clang-$LLVM_VERSION --strip-components 1
# Clang 3.5 is not able to compile the code, # OSX / Clang
# see https://travis-ci.org/nlohmann/json/jobs/126720186
# - os: linux
# compiler: clang
# addons:
# apt:
# sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
# packages: ['clang-3.6', 'valgrind']
# env: COMPILER=clang++-3.6
#
# - os: linux
# compiler: clang
# addons:
# apt:
# sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7']
# packages: ['clang-3.7', 'valgrind']
# env: COMPILER=clang++-3.7
#
# - os: linux
# compiler: clang
# addons:
# apt:
# sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8']
# packages: ['clang-3.8', 'valgrind']
# env: COMPILER=clang++-3.8
# - os: linux
# compiler: clang
# addons:
# apt:
# sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise']
# packages: ['clang-3.9', 'valgrind']
# env: COMPILER=clang++-3.9
- os: osx - os: osx
osx_image: beta-xcode6.1 osx_image: beta-xcode6.1
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: beta-xcode6.2 osx_image: beta-xcode6.2
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: beta-xcode6.3 osx_image: beta-xcode6.3
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: xcode6.4 osx_image: xcode6.4
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: xcode7.1 osx_image: xcode7.1
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: xcode7.2 osx_image: xcode7.2
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: xcode7.3 osx_image: xcode7.3
compiler: clang
env:
- COMPILER=clang
- CXXFLAGS=-lstdc++
- os: osx - os: osx
osx_image: xcode8 osx_image: xcode8
# Linux / GCC
- os: linux
compiler: gcc
env: COMPILER=g++-4.9
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: g++-4.9
- os: linux
compiler: gcc
env: COMPILER=g++-5
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: g++-5
- os: linux
compiler: gcc
env: COMPILER=g++-6
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: g++-6
# Linux / Clang
- os: linux
env: LLVM_VERSION=3.6.0
compiler: clang compiler: clang
env:
- COMPILER=clang - os: linux
- CXXFLAGS=-lstdc++ env: LLVM_VERSION=3.6.1
compiler: clang
- os: linux
env: LLVM_VERSION=3.6.2
compiler: clang
- os: linux
env: LLVM_VERSION=3.7.0
compiler: clang
- os: linux
env: LLVM_VERSION=3.7.1
compiler: clang
- os: linux
env: LLVM_VERSION=3.8.0
compiler: clang
- os: linux
env: LLVM_VERSION=3.8.1
compiler: clang
#####################
# installation step #
#####################
# set directories to cache
cache:
directories:
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.6.2
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.6.1
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.6.0
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.7.0
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.7.1
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.8.0
- ${TRAVIS_BUILD_DIR}/deps/llvm-3.8.1
install:
# create deps dir if not existing
- DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
- mkdir -p ${DEPS_DIR}
# make sure CXX is correctly set
- if [[ "${COMPILER}" != "" ]]; then export CXX=${COMPILER}; fi
# install LLVM/clang when LLVM_VERSION is set
- |
if [[ "${LLVM_VERSION}" != "" ]]; then
LLVM_DIR=${DEPS_DIR}/llvm-${LLVM_VERSION}
if [[ -z "$(ls -A ${LLVM_DIR})" ]]; then
LLVM_URL="http://llvm.org/releases/${LLVM_VERSION}/llvm-${LLVM_VERSION}.src.tar.xz"
LIBCXX_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxx-${LLVM_VERSION}.src.tar.xz"
LIBCXXABI_URL="http://llvm.org/releases/${LLVM_VERSION}/libcxxabi-${LLVM_VERSION}.src.tar.xz"
CLANG_URL="http://llvm.org/releases/${LLVM_VERSION}/clang+llvm-${LLVM_VERSION}-x86_64-linux-gnu-ubuntu-14.04.tar.xz"
mkdir -p ${LLVM_DIR} ${LLVM_DIR}/build ${LLVM_DIR}/projects/libcxx ${LLVM_DIR}/projects/libcxxabi ${LLVM_DIR}/clang
travis_retry wget --quiet -O - ${LLVM_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}
travis_retry wget --quiet -O - ${LIBCXX_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}/projects/libcxx
travis_retry wget --quiet -O - ${LIBCXXABI_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}/projects/libcxxabi
travis_retry wget --quiet -O - ${CLANG_URL} | tar --strip-components=1 -xJ -C ${LLVM_DIR}/clang
(cd ${LLVM_DIR}/build && cmake .. -DCMAKE_INSTALL_PREFIX=${LLVM_DIR}/install -DCMAKE_CXX_COMPILER=clang++)
(cd ${LLVM_DIR}/build/projects/libcxx && make install -j2)
(cd ${LLVM_DIR}/build/projects/libcxxabi && make install -j2)
fi
export CXXFLAGS="-nostdinc++ -isystem ${LLVM_DIR}/install/include/c++/v1"
export LDFLAGS="-L ${LLVM_DIR}/install/lib -l c++ -l c++abi"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${LLVM_DIR}/install/lib"
export PATH="${LLVM_DIR}/clang/bin:${PATH}"
fi
################
# build script #
################
script: script:
# show OS/compiler version
- uname -a - uname -a
- $COMPILER --version - $CXX --version
- make CXX=$COMPILER
- ./json_unit "*" # compile
- if [ `which valgrind` ]; then - make
valgrind --error-exitcode=1 --leak-check=full ./json_unit ;
fi # execute unit tests
- test/json_unit "*"
# check if homebrew works (only checks develop branch)
- if [ `which brew` ]; then - if [ `which brew` ]; then
brew update ; brew update ;
brew tap nlohmann/json ; brew tap nlohmann/json ;
brew install nlohmann_json --HEAD ; brew install nlohmann_json --HEAD ;
brew test nlohmann_json ; brew test nlohmann_json ;
fi fi
#language: cpp
#
#dist: trusty
#sudo: required
#
#env:
# global:
# # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# # via the "travis encrypt" command using the project repo's public key
# - secure: "m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA="
#
## from http://stackoverflow.com/a/32127147/266378
#matrix:
# include:
# - os: linux
# compiler: gcc
# addons:
# apt:
# sources: ['ubuntu-toolchain-r-test']
# packages: ['g++-4.9', 'valgrind', 'python-pip', 'python-yaml']
# before_script:
# - pip install --user git+git://github.com/eddyxu/cpp-coveralls.git
# after_success:
# - make clean
# - touch src/json.hpp
# - make json_unit CXXFLAGS="-fprofile-arcs -ftest-coverage -std=c++11 -lstdc++" CXX=$COMPILER
# - test/json_unit "*"
# - coveralls --build-root test --exclude src/catch.hpp --exclude src/unit-algorithms.cpp --exclude src/unit-allocator.cpp --exclude src/unit-capacity.cpp --exclude src/unit-class_const_iterator.cpp --exclude src/unit-class_iterator.cpp --exclude src/unit-class_lexer.cpp --exclude src/unit-class_parser.cpp --exclude src/unit-comparison.cpp --exclude src/unit-concepts.cpp --exclude src/unit-constructor1.cpp --exclude src/unit-constructor2.cpp --exclude src/unit-convenience.cpp --exclude src/unit-conversions.cpp --exclude src/unit-deserialization.cpp --exclude src/unit-element_access1.cpp --exclude src/unit-element_access2.cpp --exclude src/unit-inspection.cpp --exclude src/unit-iterator_wrapper.cpp --exclude src/unit-iterators1.cpp --exclude src/unit-iterators2.cpp --exclude src/unit-json_patch.cpp --exclude src/unit-json_pointer.cpp --exclude src/unit-modifiers.cpp --exclude src/unit-pointer_access.cpp --exclude src/unit-readme.cpp --exclude src/unit-reference_access.cpp --exclude src/unit-regression.cpp --exclude src/unit-serialization.cpp --exclude src/unit-testsuites.cpp --exclude src/unit-unicode.cpp --include ../src/json.hpp --gcov-options '\-lp' --gcov 'gcov-4.9'
# env: COMPILER=g++-4.9
#
# - os: linux
# compiler: gcc
# before_install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt
# addons:
# apt:
# sources: ['ubuntu-toolchain-r-test']
# packages: ['g++-5', 'valgrind']
# coverity_scan:
# project:
# name: "nlohmann/json"
# description: "Build submitted via Travis CI"
# notification_email: niels.lohmann@gmail.com
# build_command_prepend: "make clean ; sudo cp $(which g++-5) $(which g++)"
# build_command: "make"
# branch_pattern: coverity_scan
# env: COMPILER=g++-5
#

View File

@ -12,18 +12,23 @@ clean:
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM
rm -fr benchmarks/files/numbers/*.json rm -fr benchmarks/files/numbers/*.json
$(MAKE) clean -Cdoc $(MAKE) clean -Cdoc
$(MAKE) clean -Ctest
########################################################################## ##########################################################################
# unit tests # unit tests
########################################################################## ##########################################################################
# additional flags # build unit tests
FLAGS = -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wfloat-equal json_unit:
@$(MAKE) -C test
# build unit tests (TODO: Does this want its own makefile?) # run unit tests
json_unit: test/src/unit.cpp src/json.hpp test/src/catch.hpp check: json_unit
$(CXX) -std=c++11 $(CXXFLAGS) $(FLAGS) $(CPPFLAGS) -I src -I test $< $(LDFLAGS) -o $@ test/json_unit "*"
check-fast: json_unit
test/json_unit
########################################################################## ##########################################################################
@ -59,8 +64,7 @@ fuzz: test/src/fuzz.cpp src/json.hpp
# call cppcheck on the main header file # call cppcheck on the main header file
cppcheck: cppcheck:
cppcheck --enable=all --inconclusive --std=c++11 src/json.hpp cppcheck --enable=warning --inconclusive --force --std=c++11 src/json.hpp --error-exitcode=1
########################################################################## ##########################################################################
# maintainer targets # maintainer targets
@ -77,7 +81,8 @@ pretty:
--indent-col1-comments --pad-oper --pad-header --align-pointer=type \ --indent-col1-comments --pad-oper --pad-header --align-pointer=type \
--align-reference=type --add-brackets --convert-tabs --close-templates \ --align-reference=type --add-brackets --convert-tabs --close-templates \
--lineend=linux --preserve-date --suffix=none --formatted \ --lineend=linux --preserve-date --suffix=none --formatted \
src/json.hpp src/json.hpp.re2c test/src/unit.cpp test/src/fuzz.cpp benchmarks/benchmarks.cpp doc/examples/*.cpp src/json.hpp src/json.hpp.re2c test/src/*.cpp \
benchmarks/benchmarks.cpp doc/examples/*.cpp
########################################################################## ##########################################################################
@ -87,7 +92,7 @@ pretty:
# benchmarks # benchmarks
json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp
cd benchmarks/files/numbers ; python generate.py cd benchmarks/files/numbers ; python generate.py
$(CXX) -std=c++11 $(CXXFLAGS) -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@ $(CXX) -std=c++11 $(CXXFLAGS) -DNDEBUG -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@
./json_benchmarks ./json_benchmarks

View File

@ -9,6 +9,7 @@
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
[![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) [![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases)
[![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues) [![Github Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289)
## Design goals ## Design goals
@ -18,7 +19,7 @@ There are myriads of [JSON](http://json.org) libraries out there, and each may e
- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/src/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. - **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/src/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.
- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. - **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289).
Other aspects were not so important to us: Other aspects were not so important to us:
@ -416,7 +417,13 @@ The following compilers are currently used in continuous integration at [Travis]
| GCC 4.9.3 | Ubuntu 14.04.4 LTS | g++-4.9 (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 | | GCC 4.9.3 | Ubuntu 14.04.4 LTS | g++-4.9 (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 |
| GCC 5.3.0 | Ubuntu 14.04.4 LTS | g++-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204 | | GCC 5.3.0 | Ubuntu 14.04.4 LTS | g++-5 (Ubuntu 5.3.0-3ubuntu1~14.04) 5.3.0 20151204 |
| GCC 6.1.1 | Ubuntu 14.04.4 LTS | g++-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511 | | GCC 6.1.1 | Ubuntu 14.04.4 LTS | g++-6 (Ubuntu 6.1.1-3ubuntu11~14.04.1) 6.1.1 20160511 |
| Clang 3.6.0 | Ubuntu 14.04.4 LTS | clang version 3.6.0 (tags/RELEASE_360/final) |
| Clang 3.6.1 | Ubuntu 14.04.4 LTS | clang version 3.6.1 (tags/RELEASE_361/final) |
| Clang 3.6.2 | Ubuntu 14.04.4 LTS | clang version 3.6.2 (tags/RELEASE_362/final) |
| Clang 3.7.0 | Ubuntu 14.04.4 LTS | clang version 3.7.0 (tags/RELEASE_370/final) |
| Clang 3.7.1 | Ubuntu 14.04.4 LTS | clang version 3.7.1 (tags/RELEASE_371/final) |
| Clang 3.8.0 | Ubuntu 14.04.4 LTS | clang version 3.8.0 (tags/RELEASE_380/final) | | Clang 3.8.0 | Ubuntu 14.04.4 LTS | clang version 3.8.0 (tags/RELEASE_380/final) |
| Clang 3.8.1 | Ubuntu 14.04.4 LTS | clang version 3.8.1 (tags/RELEASE_381/final) |
| Clang Xcode 6.1 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) | | Clang Xcode 6.1 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) |
| Clang Xcode 6.2 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) | | Clang Xcode 6.2 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) |
| Clang Xcode 6.3 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn) | | Clang Xcode 6.3 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn) |
@ -492,7 +499,7 @@ Thanks a lot for helping out!
## Notes ## Notes
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). - The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726).
- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
@ -501,11 +508,10 @@ Thanks a lot for helping out!
To compile and run the tests, you need to execute To compile and run the tests, you need to execute
```sh ```sh
$ make $ make check
$ ./json_unit "*"
=============================================================================== ===============================================================================
All tests passed (8905012 assertions in 32 test cases) All tests passed (8905099 assertions in 32 test cases)
``` ```
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 440 KiB

After

Width:  |  Height:  |  Size: 440 KiB

View File

@ -1843,7 +1843,8 @@ class basic_json
@param[in] first begin of the range to copy from (included) @param[in] first begin of the range to copy from (included)
@param[in] last end of the range to copy from (excluded) @param[in] last end of the range to copy from (excluded)
@pre Iterators @a first and @a last must be initialized. @pre Iterators @a first and @a last must be initialized. **This
precondition is enforced with an assertion.**
@throw std::domain_error if iterators are not compatible; that is, do not @throw std::domain_error if iterators are not compatible; that is, do not
belong to the same JSON value; example: `"iterators are not compatible"` belong to the same JSON value; example: `"iterators are not compatible"`
@ -3509,6 +3510,9 @@ class basic_json
@return const reference to the element at key @a key @return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw std::domain_error if JSON is not an object; example: `"cannot use @throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"` operator[] with null"`
@ -3667,6 +3671,9 @@ class basic_json
@return const reference to the element at key @a key @return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw std::domain_error if JSON is not an object; example: `"cannot use @throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"` operator[] with null"`
@ -3867,7 +3874,8 @@ class basic_json
@complexity Constant. @complexity Constant.
@pre The JSON value must not be `null` (would throw `std::out_of_range`) @pre The JSON value must not be `null` (would throw `std::out_of_range`)
or an empty array or object (undefined behavior, guarded by assertions). or an empty array or object (undefined behavior, **guarded by
assertions**).
@post The JSON value remains unchanged. @post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value @throw std::out_of_range when called on `null` value
@ -3909,7 +3917,8 @@ class basic_json
@complexity Constant. @complexity Constant.
@pre The JSON value must not be `null` (would throw `std::out_of_range`) @pre The JSON value must not be `null` (would throw `std::out_of_range`)
or an empty array or object (undefined behavior, guarded by assertions). or an empty array or object (undefined behavior, **guarded by
assertions**).
@post The JSON value remains unchanged. @post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value. @throw std::out_of_range when called on `null` value.
@ -6592,8 +6601,8 @@ class basic_json
@note An iterator is called *initialized* when a pointer to a JSON value @note An iterator is called *initialized* when a pointer to a JSON value
has been set (e.g., by a constructor or a copy assignment). If the has been set (e.g., by a constructor or a copy assignment). If the
iterator is default-constructed, it is *uninitialized* and most iterator is default-constructed, it is *uninitialized* and most
methods are undefined. The library uses assertions to detect calls methods are undefined. **The library uses assertions to detect calls
on uninitialized iterators. on uninitialized iterators.**
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
@ -7725,7 +7734,7 @@ class basic_json
}; };
if ((m_limit - m_cursor) < 5) if ((m_limit - m_cursor) < 5)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yybm[0 + yych] & 32) if (yybm[0 + yych] & 32)
@ -7859,7 +7868,7 @@ basic_json_parser_6:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yybm[0 + yych] & 32) if (yybm[0 + yych] & 32)
@ -7929,7 +7938,7 @@ basic_json_parser_15:
m_marker = ++m_cursor; m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3) if ((m_limit - m_cursor) < 3)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yybm[0 + yych] & 64) if (yybm[0 + yych] & 64)
@ -8022,7 +8031,7 @@ basic_json_parser_31:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
basic_json_parser_32: basic_json_parser_32:
@ -8059,7 +8068,7 @@ basic_json_parser_36:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= 'e') if (yych <= 'e')
@ -8203,7 +8212,7 @@ basic_json_parser_43:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= '@') if (yych <= '@')
@ -8239,7 +8248,7 @@ basic_json_parser_44:
m_marker = ++m_cursor; m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3) if ((m_limit - m_cursor) < 3)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= 'D') if (yych <= 'D')
@ -8280,7 +8289,7 @@ basic_json_parser_47:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= '/') if (yych <= '/')
@ -8322,7 +8331,7 @@ basic_json_parser_54:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= '@') if (yych <= '@')
@ -8376,7 +8385,7 @@ basic_json_parser_60:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= '@') if (yych <= '@')
@ -8417,7 +8426,7 @@ basic_json_parser_63:
++m_cursor; ++m_cursor;
if (m_limit <= m_cursor) if (m_limit <= m_cursor)
{ {
yyfill(); // LCOV_EXCL_LINE; yyfill();
} }
yych = *m_cursor; yych = *m_cursor;
if (yych <= '@') if (yych <= '@')
@ -8883,7 +8892,8 @@ basic_json_parser_63:
{ {
case lexer::token_type::begin_object: case lexer::token_type::begin_object:
{ {
if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) if (keep and (not callback
or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
{ {
// explicitly set result to object to cope with {} // explicitly set result to object to cope with {}
result.m_type = value_t::object; result.m_type = value_t::object;
@ -8961,7 +8971,8 @@ basic_json_parser_63:
case lexer::token_type::begin_array: case lexer::token_type::begin_array:
{ {
if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) if (keep and (not callback
or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
{ {
// explicitly set result to object to cope with [] // explicitly set result to object to cope with []
result.m_type = value_t::array; result.m_type = value_t::array;
@ -9475,7 +9486,7 @@ basic_json_parser_63:
} }
/// split the string input to reference tokens /// split the string input to reference tokens
static std::vector<std::string> split(std::string reference_string) static std::vector<std::string> split(const std::string& reference_string)
{ {
std::vector<std::string> result; std::vector<std::string> result;
@ -10203,7 +10214,7 @@ basic_json_parser_63:
*/ */
static basic_json diff(const basic_json& source, static basic_json diff(const basic_json& source,
const basic_json& target, const basic_json& target,
std::string path = "") const std::string& path = "")
{ {
// the patch // the patch
basic_json result(value_t::array); basic_json result(value_t::array);

View File

@ -1843,7 +1843,8 @@ class basic_json
@param[in] first begin of the range to copy from (included) @param[in] first begin of the range to copy from (included)
@param[in] last end of the range to copy from (excluded) @param[in] last end of the range to copy from (excluded)
@pre Iterators @a first and @a last must be initialized. @pre Iterators @a first and @a last must be initialized. **This
precondition is enforced with an assertion.**
@throw std::domain_error if iterators are not compatible; that is, do not @throw std::domain_error if iterators are not compatible; that is, do not
belong to the same JSON value; example: `"iterators are not compatible"` belong to the same JSON value; example: `"iterators are not compatible"`
@ -3509,6 +3510,9 @@ class basic_json
@return const reference to the element at key @a key @return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw std::domain_error if JSON is not an object; example: `"cannot use @throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"` operator[] with null"`
@ -3667,6 +3671,9 @@ class basic_json
@return const reference to the element at key @a key @return const reference to the element at key @a key
@pre The element with key @a key must exist. **This precondition is
enforced with an assertion.**
@throw std::domain_error if JSON is not an object; example: `"cannot use @throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"` operator[] with null"`
@ -3867,7 +3874,8 @@ class basic_json
@complexity Constant. @complexity Constant.
@pre The JSON value must not be `null` (would throw `std::out_of_range`) @pre The JSON value must not be `null` (would throw `std::out_of_range`)
or an empty array or object (undefined behavior, guarded by assertions). or an empty array or object (undefined behavior, **guarded by
assertions**).
@post The JSON value remains unchanged. @post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value @throw std::out_of_range when called on `null` value
@ -3909,7 +3917,8 @@ class basic_json
@complexity Constant. @complexity Constant.
@pre The JSON value must not be `null` (would throw `std::out_of_range`) @pre The JSON value must not be `null` (would throw `std::out_of_range`)
or an empty array or object (undefined behavior, guarded by assertions). or an empty array or object (undefined behavior, **guarded by
assertions**).
@post The JSON value remains unchanged. @post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value. @throw std::out_of_range when called on `null` value.
@ -6592,8 +6601,8 @@ class basic_json
@note An iterator is called *initialized* when a pointer to a JSON value @note An iterator is called *initialized* when a pointer to a JSON value
has been set (e.g., by a constructor or a copy assignment). If the has been set (e.g., by a constructor or a copy assignment). If the
iterator is default-constructed, it is *uninitialized* and most iterator is default-constructed, it is *uninitialized* and most
methods are undefined. The library uses assertions to detect calls methods are undefined. **The library uses assertions to detect calls
on uninitialized iterators. on uninitialized iterators.**
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
@ -7689,7 +7698,7 @@ class basic_json
re2c:define:YYCURSOR = m_cursor; re2c:define:YYCURSOR = m_cursor;
re2c:define:YYLIMIT = m_limit; re2c:define:YYLIMIT = m_limit;
re2c:define:YYMARKER = m_marker; re2c:define:YYMARKER = m_marker;
re2c:define:YYFILL = "yyfill(); // LCOV_EXCL_LINE"; re2c:define:YYFILL = "yyfill()";
re2c:yyfill:parameter = 0; re2c:yyfill:parameter = 0;
re2c:indent:string = " "; re2c:indent:string = " ";
re2c:indent:top = 1; re2c:indent:top = 1;
@ -8180,7 +8189,8 @@ class basic_json
{ {
case lexer::token_type::begin_object: case lexer::token_type::begin_object:
{ {
if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result)))) if (keep and (not callback
or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
{ {
// explicitly set result to object to cope with {} // explicitly set result to object to cope with {}
result.m_type = value_t::object; result.m_type = value_t::object;
@ -8258,7 +8268,8 @@ class basic_json
case lexer::token_type::begin_array: case lexer::token_type::begin_array:
{ {
if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result)))) if (keep and (not callback
or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
{ {
// explicitly set result to object to cope with [] // explicitly set result to object to cope with []
result.m_type = value_t::array; result.m_type = value_t::array;
@ -8772,7 +8783,7 @@ class basic_json
} }
/// split the string input to reference tokens /// split the string input to reference tokens
static std::vector<std::string> split(std::string reference_string) static std::vector<std::string> split(const std::string& reference_string)
{ {
std::vector<std::string> result; std::vector<std::string> result;
@ -9500,7 +9511,7 @@ class basic_json
*/ */
static basic_json diff(const basic_json& source, static basic_json diff(const basic_json& source,
const basic_json& target, const basic_json& target,
std::string path = "") const std::string& path = "")
{ {
// the patch // the patch
basic_json result(value_t::array); basic_json result(value_t::array);

View File

@ -3,6 +3,36 @@ set(JSON_UNITTEST_TARGET_NAME "json_unit")
add_executable(${JSON_UNITTEST_TARGET_NAME} add_executable(${JSON_UNITTEST_TARGET_NAME}
"src/catch.hpp" "src/catch.hpp"
"src/unit.cpp" "src/unit.cpp"
"src/unit-algorithms.cpp"
"src/unit-allocator.cpp"
"src/unit-capacity.cpp"
"src/unit-class_const_iterator.cpp"
"src/unit-class_iterator.cpp"
"src/unit-class_lexer.cpp"
"src/unit-class_parser.cpp"
"src/unit-comparison.cpp"
"src/unit-concepts.cpp"
"src/unit-constructor1.cpp"
"src/unit-constructor2.cpp"
"src/unit-convenience.cpp"
"src/unit-conversions.cpp"
"src/unit-deserialization.cpp"
"src/unit-element_access1.cpp"
"src/unit-element_access2.cpp"
"src/unit-inspection.cpp"
"src/unit-iterator_wrapper.cpp"
"src/unit-iterators1.cpp"
"src/unit-iterators2.cpp"
"src/unit-json_patch.cpp"
"src/unit-json_pointer.cpp"
"src/unit-modifiers.cpp"
"src/unit-pointer_access.cpp"
"src/unit-readme.cpp"
"src/unit-reference_access.cpp"
"src/unit-regression.cpp"
"src/unit-serialization.cpp"
"src/unit-testsuites.cpp"
"src/unit-unicode.cpp"
) )
set_target_properties(${JSON_UNITTEST_TARGET_NAME} PROPERTIES set_target_properties(${JSON_UNITTEST_TARGET_NAME} PROPERTIES

54
test/Makefile Normal file
View File

@ -0,0 +1,54 @@
##########################################################################
# unit tests
##########################################################################
# additional flags
CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Weffc++ -Wcast-align -Wcast-qual -Wno-ctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wno-float-equal
CPPFLAGS += -I ../src -I .
SOURCES = src/unit.cpp \
src/unit-algorithms.cpp \
src/unit-allocator.cpp \
src/unit-capacity.cpp \
src/unit-class_const_iterator.cpp \
src/unit-class_iterator.cpp \
src/unit-class_lexer.cpp \
src/unit-class_parser.cpp \
src/unit-comparison.cpp \
src/unit-concepts.cpp \
src/unit-constructor1.cpp \
src/unit-constructor2.cpp \
src/unit-convenience.cpp \
src/unit-conversions.cpp \
src/unit-deserialization.cpp \
src/unit-element_access1.cpp \
src/unit-element_access2.cpp \
src/unit-inspection.cpp \
src/unit-iterator_wrapper.cpp \
src/unit-iterators1.cpp \
src/unit-iterators2.cpp \
src/unit-json_patch.cpp \
src/unit-json_pointer.cpp \
src/unit-modifiers.cpp \
src/unit-pointer_access.cpp \
src/unit-readme.cpp \
src/unit-reference_access.cpp \
src/unit-regression.cpp \
src/unit-serialization.cpp \
src/unit-unicode.cpp \
src/unit-testsuites.cpp
OBJECTS = $(SOURCES:.cpp=.o)
all: json_unit
json_unit: $(OBJECTS) ../src/json.hpp src/catch.hpp
@echo "[CXXLD] $@"
@$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJECTS) -o $@
%.o: %.cpp ../src/json.hpp src/catch.hpp
@echo "[CXX] $@"
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
clean:
rm -fr json_unit $(OBJECTS) $(SOURCES:.cpp=.gcno) $(SOURCES:.cpp=.gcda)

View File

@ -0,0 +1,318 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("algorithms")
{
json j_array = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz"};
json j_object = {{"one", 1}, {"two", 2}};
SECTION("non-modifying sequence operations")
{
SECTION("std::all_of")
{
CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json & value)
{
return value.size() > 0;
}));
CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json & value)
{
return value.type() == json::value_t::number_integer;
}));
}
SECTION("std::any_of")
{
CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
{
return value.is_string() and value.get<std::string>() == "foo";
}));
CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
{
return value.get<int>() > 1;
}));
}
SECTION("std::none_of")
{
CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json & value)
{
return value.size() == 0;
}));
CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json & value)
{
return value.get<int>() <= 0;
}));
}
SECTION("std::for_each")
{
SECTION("reading")
{
int sum = 0;
std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value)
{
if (value.is_number())
{
sum += static_cast<int>(value);
}
});
CHECK(sum == 45);
}
SECTION("writing")
{
auto add17 = [](json & value)
{
if (value.is_array())
{
value.push_back(17);
}
};
std::for_each(j_array.begin(), j_array.end(), add17);
CHECK(j_array[6] == json({1, 2, 3, 17}));
}
}
SECTION("std::count")
{
CHECK(std::count(j_array.begin(), j_array.end(), json(true)) == 1);
}
SECTION("std::count_if")
{
CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json & value)
{
return (value.is_number());
}) == 3);
CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&)
{
return true;
}) == 9);
}
SECTION("std::mismatch")
{
json j_array2 = {13, 29, 3, {{"one", 1}, {"two", 2}, {"three", 3}}, true, false, {1, 2, 3}, "foo", "baz"};
auto res = std::mismatch(j_array.begin(), j_array.end(), j_array2.begin());
CHECK(*res.first == json({{"one", 1}, {"two", 2}}));
CHECK(*res.second == json({{"one", 1}, {"two", 2}, {"three", 3}}));
}
SECTION("std::equal")
{
SECTION("using operator==")
{
CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
CHECK(not std::equal(j_array.begin(), j_array.end(), j_object.begin()));
}
SECTION("using user-defined comparison")
{
// compare objects only by size of its elements
json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
CHECK(not std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
[](const json & a, const json & b)
{
return (a.size() == b.size());
}));
}
}
SECTION("std::find")
{
auto it = std::find(j_array.begin(), j_array.end(), json(false));
CHECK(std::distance(j_array.begin(), it) == 5);
}
SECTION("std::find_if")
{
auto it = std::find_if(j_array.begin(), j_array.end(),
[](const json & value)
{
return value.is_boolean();
});
CHECK(std::distance(j_array.begin(), it) == 4);
}
SECTION("std::find_if_not")
{
auto it = std::find_if_not(j_array.begin(), j_array.end(),
[](const json & value)
{
return value.is_number();
});
CHECK(std::distance(j_array.begin(), it) == 3);
}
SECTION("std::adjacent_find")
{
CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end());
CHECK(std::adjacent_find(j_array.begin(), j_array.end(),
[](const json & v1, const json & v2)
{
return v1.type() == v2.type();
}) == j_array.begin());
}
}
SECTION("modifying sequence operations")
{
SECTION("std::reverse")
{
std::reverse(j_array.begin(), j_array.end());
CHECK(j_array == json({"baz", "foo", {1, 2, 3}, false, true, {{"one", 1}, {"two", 2}}, 3, 29, 13}));
}
SECTION("std::rotate")
{
std::rotate(j_array.begin(), j_array.begin() + 1, j_array.end());
CHECK(j_array == json({29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", 13}));
}
SECTION("std::partition")
{
auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v)
{
return v.is_string();
});
CHECK(std::distance(j_array.begin(), it) == 2);
CHECK(not it[2].is_string());
}
}
SECTION("sorting operations")
{
SECTION("std::sort")
{
SECTION("with standard comparison")
{
json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
std::sort(j.begin(), j.end());
CHECK(j == json({nullptr, false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
}
SECTION("with user-defined comparison")
{
json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr};
std::sort(j.begin(), j.end(), [](const json & a, const json & b)
{
return a.size() < b.size();
});
CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}}));
}
SECTION("sorting an object")
{
json j({{"one", 1}, {"two", 2}});
CHECK_THROWS_AS(std::sort(j.begin(), j.end()), std::domain_error);
CHECK_THROWS_WITH(std::sort(j.begin(), j.end()), "cannot use offsets with object iterators");
}
}
SECTION("std::partial_sort")
{
json j = {13, 29, 3, {{"one", 1}, {"two", 2}}, true, false, {1, 2, 3}, "foo", "baz", nullptr};
std::partial_sort(j.begin(), j.begin() + 4, j.end());
CHECK(j == json({nullptr, false, true, 3, {{"one", 1}, {"two", 2}}, 29, {1, 2, 3}, "foo", "baz", 13}));
}
}
SECTION("set operations")
{
SECTION("std::merge")
{
{
json j1 = {2, 4, 6, 8};
json j2 = {1, 2, 3, 5, 7};
json j3;
std::merge(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
CHECK(j3 == json({1, 2, 2, 3, 4, 5, 6, 7, 8}));
}
}
SECTION("std::set_difference")
{
json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
json j2 = {1, 2, 3, 5, 7};
json j3;
std::set_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
CHECK(j3 == json({4, 6, 8}));
}
SECTION("std::set_intersection")
{
json j1 = {1, 2, 3, 4, 5, 6, 7, 8};
json j2 = {1, 2, 3, 5, 7};
json j3;
std::set_intersection(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
CHECK(j3 == json({1, 2, 3, 5, 7}));
}
SECTION("std::set_union")
{
json j1 = {2, 4, 6, 8};
json j2 = {1, 2, 3, 5, 7};
json j3;
std::set_union(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
CHECK(j3 == json({1, 2, 3, 4, 5, 6, 7, 8}));
}
SECTION("std::set_symmetric_difference")
{
json j1 = {2, 4, 6, 8};
json j2 = {1, 2, 3, 5, 7};
json j3;
std::set_symmetric_difference(j1.begin(), j1.end(), j2.begin(), j2.end(), std::back_inserter(j3));
CHECK(j3 == json({1, 3, 4, 5, 6, 7, 8}));
}
}
SECTION("heap operations")
{
std::make_heap(j_array.begin(), j_array.end());
CHECK(std::is_heap(j_array.begin(), j_array.end()));
std::sort_heap(j_array.begin(), j_array.end());
CHECK(j_array == json({false, true, 3, 13, 29, {{"one", 1}, {"two", 2}}, {1, 2, 3}, "baz", "foo"}));
}
}

234
test/src/unit-allocator.cpp Normal file
View File

@ -0,0 +1,234 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
// special test case to check if memory is leaked if constructor throws
template<class T>
struct bad_allocator : std::allocator<T>
{
template<class... Args>
void construct(T*, Args&& ...)
{
throw std::bad_alloc();
}
};
TEST_CASE("bad_alloc")
{
SECTION("bad_alloc")
{
// create JSON type using the throwing allocator
using bad_json = nlohmann::basic_json<std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
bad_allocator>;
// creating an object should throw
CHECK_THROWS_AS(bad_json j(bad_json::value_t::object), std::bad_alloc);
}
}
bool next_construct_fails = false;
bool next_destroy_fails = false;
bool next_deallocate_fails = false;
template<class T>
struct my_allocator : std::allocator<T>
{
template<class... Args>
void construct(T* p, Args&& ... args)
{
if (next_construct_fails)
{
next_construct_fails = false;
throw std::bad_alloc();
}
else
{
::new(reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
}
}
void deallocate(T* p, std::size_t n)
{
if (next_deallocate_fails)
{
next_deallocate_fails = false;
throw std::bad_alloc();
}
else
{
std::allocator<T>::deallocate(p, n);
}
}
void destroy(T* p)
{
if (next_destroy_fails)
{
next_destroy_fails = false;
throw std::bad_alloc();
}
else
{
p->~T();
}
}
};
TEST_CASE("controlled bad_alloc")
{
// create JSON type using the throwing allocator
using my_json = nlohmann::basic_json<std::map,
std::vector,
std::string,
bool,
std::int64_t,
std::uint64_t,
double,
my_allocator>;
SECTION("class json_value")
{
SECTION("json_value(value_t)")
{
SECTION("object")
{
next_construct_fails = false;
auto t = my_json::value_t::object;
CHECK_NOTHROW(my_json::json_value j(t));
next_construct_fails = true;
CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
next_construct_fails = false;
}
SECTION("array")
{
next_construct_fails = false;
auto t = my_json::value_t::array;
CHECK_NOTHROW(my_json::json_value j(t));
next_construct_fails = true;
CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
next_construct_fails = false;
}
SECTION("string")
{
next_construct_fails = false;
auto t = my_json::value_t::string;
CHECK_NOTHROW(my_json::json_value j(t));
next_construct_fails = true;
CHECK_THROWS_AS(my_json::json_value j(t), std::bad_alloc);
next_construct_fails = false;
}
}
SECTION("json_value(const string_t&)")
{
next_construct_fails = false;
my_json::string_t v("foo");
CHECK_NOTHROW(my_json::json_value j(v));
next_construct_fails = true;
CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
next_construct_fails = false;
}
/*
SECTION("json_value(const object_t&)")
{
next_construct_fails = false;
my_json::object_t v {{"foo", "bar"}};
CHECK_NOTHROW(my_json::json_value j(v));
next_construct_fails = true;
CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
next_construct_fails = false;
}
*/
/*
SECTION("json_value(const array_t&)")
{
next_construct_fails = false;
my_json::array_t v = {"foo", "bar", "baz"};
CHECK_NOTHROW(my_json::json_value j(v));
next_construct_fails = true;
CHECK_THROWS_AS(my_json::json_value j(v), std::bad_alloc);
next_construct_fails = false;
}
*/
}
SECTION("class basic_json")
{
SECTION("basic_json(const CompatibleObjectType&)")
{
next_construct_fails = false;
std::map<std::string, std::string> v {{"foo", "bar"}};
CHECK_NOTHROW(my_json j(v));
next_construct_fails = true;
CHECK_THROWS_AS(my_json j(v), std::bad_alloc);
next_construct_fails = false;
}
SECTION("basic_json(const CompatibleArrayType&)")
{
next_construct_fails = false;
std::vector<std::string> v {"foo", "bar", "baz"};
CHECK_NOTHROW(my_json j(v));
next_construct_fails = true;
CHECK_THROWS_AS(my_json j(v), std::bad_alloc);
next_construct_fails = false;
}
SECTION("basic_json(const typename string_t::value_type*)")
{
next_construct_fails = false;
CHECK_NOTHROW(my_json v("foo"));
next_construct_fails = true;
CHECK_THROWS_AS(my_json v("foo"), std::bad_alloc);
next_construct_fails = false;
}
SECTION("basic_json(const typename string_t::value_type*)")
{
next_construct_fails = false;
std::string s("foo");
CHECK_NOTHROW(my_json v(s));
next_construct_fails = true;
CHECK_THROWS_AS(my_json v(s), std::bad_alloc);
next_construct_fails = false;
}
}
}

562
test/src/unit-capacity.cpp Normal file
View File

@ -0,0 +1,562 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("capacity")
{
SECTION("empty()")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == true);
CHECK(j_const.empty() == true);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("filled array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == true);
CHECK(j_const.empty() == true);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("number (unsigned)")
{
json j = 23u;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == false);
CHECK(j_const.empty() == false);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("result of empty")
{
CHECK(j.empty() == true);
CHECK(j_const.empty() == true);
}
SECTION("definition of empty")
{
CHECK(j.empty() == (j.begin() == j.end()));
CHECK(j_const.empty() == (j_const.begin() == j_const.end()));
}
}
}
SECTION("size()")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 0);
CHECK(j_const.size() == 0);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("filled array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 3);
CHECK(j_const.size() == 3);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 0);
CHECK(j_const.size() == 0);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 3);
CHECK(j_const.size() == 3);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("number (unsigned)")
{
json j = 23u;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 1);
CHECK(j_const.size() == 1);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("result of size")
{
CHECK(j.size() == 0);
CHECK(j_const.size() == 0);
}
SECTION("definition of size")
{
CHECK(std::distance(j.begin(), j.end()) == j.size());
CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size());
CHECK(std::distance(j.rbegin(), j.rend()) == j.size());
CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size());
}
}
}
SECTION("max_size()")
{
SECTION("boolean")
{
json j = true;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("string")
{
json j = "hello world";
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
SECTION("filled array")
{
json j = {1, 2, 3};
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() >= j.size());
CHECK(j_const.max_size() >= j_const.size());
}
}
}
SECTION("number (integer)")
{
json j = 23;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("number (unsigned)")
{
json j = 23u;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("number (float)")
{
json j = 23.42;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 1);
CHECK(j_const.max_size() == 1);
}
}
SECTION("null")
{
json j = nullptr;
json j_const(j);
SECTION("result of max_size")
{
CHECK(j.max_size() == 0);
CHECK(j_const.max_size() == 0);
}
}
}
}

View File

@ -0,0 +1,401 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
TEST_CASE("const_iterator class")
{
SECTION("construction")
{
SECTION("constructor")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it(&j);
}
SECTION("object")
{
json j(json::value_t::object);
json::const_iterator it(&j);
}
SECTION("array")
{
json j(json::value_t::array);
json::const_iterator it(&j);
}
}
SECTION("copy assignment")
{
json j(json::value_t::null);
json::const_iterator it(&j);
json::const_iterator it2(&j);
it2 = it;
}
}
SECTION("initialization")
{
SECTION("set_begin")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it(&j);
it.set_begin();
CHECK(it == j.cbegin());
}
SECTION("object")
{
json j(json::value_t::object);
json::const_iterator it(&j);
it.set_begin();
CHECK(it == j.cbegin());
}
SECTION("array")
{
json j(json::value_t::array);
json::const_iterator it(&j);
it.set_begin();
CHECK(it == j.cbegin());
}
}
SECTION("set_end")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it(&j);
it.set_end();
CHECK(it == j.cend());
}
SECTION("object")
{
json j(json::value_t::object);
json::const_iterator it(&j);
it.set_end();
CHECK(it == j.cend());
}
SECTION("array")
{
json j(json::value_t::array);
json::const_iterator it(&j);
it.set_end();
CHECK(it == j.cend());
}
}
}
SECTION("element access")
{
SECTION("operator*")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK_THROWS_AS(*it, std::out_of_range);
CHECK_THROWS_WITH(*it, "cannot get value");
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(*it == json(17));
it = j.cend();
CHECK_THROWS_AS(*it, std::out_of_range);
CHECK_THROWS_WITH(*it, "cannot get value");
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(*it == json("bar"));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(*it == json(1));
}
}
SECTION("operator->")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(it->type_name() == "number");
it = j.cend();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(it->type_name() == "string");
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(it->type_name() == "number");
}
}
}
SECTION("increment/decrement")
{
SECTION("post-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.primitive_iterator == 1);
it++;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.primitive_iterator == 0);
it++;
CHECK(it.m_it.primitive_iterator == 1);
it++;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
it++;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("pre-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.primitive_iterator == 1);
++it;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cbegin();
CHECK(it.m_it.primitive_iterator == 0);
++it;
CHECK(it.m_it.primitive_iterator == 1);
++it;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
++it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("post-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cend();
CHECK(it.m_it.primitive_iterator == 1);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cend();
CHECK(it.m_it.primitive_iterator == 1);
it--;
CHECK(it.m_it.primitive_iterator == 0);
it--;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cend();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
it--;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cend();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
SECTION("pre-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::const_iterator it = j.cend();
CHECK(it.m_it.primitive_iterator == 1);
}
SECTION("number")
{
json j(17);
json::const_iterator it = j.cend();
CHECK(it.m_it.primitive_iterator == 1);
--it;
CHECK(it.m_it.primitive_iterator == 0);
--it;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::const_iterator it = j.cend();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
--it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::const_iterator it = j.cend();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
}
}

View File

@ -0,0 +1,401 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
TEST_CASE("iterator class")
{
SECTION("construction")
{
SECTION("constructor")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it(&j);
}
SECTION("object")
{
json j(json::value_t::object);
json::iterator it(&j);
}
SECTION("array")
{
json j(json::value_t::array);
json::iterator it(&j);
}
}
SECTION("copy assignment")
{
json j(json::value_t::null);
json::iterator it(&j);
json::iterator it2(&j);
it2 = it;
}
}
SECTION("initialization")
{
SECTION("set_begin")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it(&j);
it.set_begin();
CHECK(it == j.begin());
}
SECTION("object")
{
json j(json::value_t::object);
json::iterator it(&j);
it.set_begin();
CHECK(it == j.begin());
}
SECTION("array")
{
json j(json::value_t::array);
json::iterator it(&j);
it.set_begin();
CHECK(it == j.begin());
}
}
SECTION("set_end")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it(&j);
it.set_end();
CHECK(it == j.end());
}
SECTION("object")
{
json j(json::value_t::object);
json::iterator it(&j);
it.set_end();
CHECK(it == j.end());
}
SECTION("array")
{
json j(json::value_t::array);
json::iterator it(&j);
it.set_end();
CHECK(it == j.end());
}
}
}
SECTION("element access")
{
SECTION("operator*")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK_THROWS_AS(*it, std::out_of_range);
CHECK_THROWS_WITH(*it, "cannot get value");
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(*it == json(17));
it = j.end();
CHECK_THROWS_AS(*it, std::out_of_range);
CHECK_THROWS_WITH(*it, "cannot get value");
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(*it == json("bar"));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(*it == json(1));
}
}
SECTION("operator->")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(it->type_name() == "number");
it = j.end();
CHECK_THROWS_AS(it->type_name(), std::out_of_range);
CHECK_THROWS_WITH(it->type_name(), "cannot get value");
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(it->type_name() == "string");
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(it->type_name() == "number");
}
}
}
SECTION("increment/decrement")
{
SECTION("post-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK(it.m_it.primitive_iterator == 1);
it++;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(it.m_it.primitive_iterator == 0);
it++;
CHECK(it.m_it.primitive_iterator == 1);
it++;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
it++;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it++;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("pre-increment")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.begin();
CHECK(it.m_it.primitive_iterator == 1);
++it;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("number")
{
json j(17);
json::iterator it = j.begin();
CHECK(it.m_it.primitive_iterator == 0);
++it;
CHECK(it.m_it.primitive_iterator == 1);
++it;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
++it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
++it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
}
}
SECTION("post-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.end();
CHECK(it.m_it.primitive_iterator == 1);
}
SECTION("number")
{
json j(17);
json::iterator it = j.end();
CHECK(it.m_it.primitive_iterator == 1);
it--;
CHECK(it.m_it.primitive_iterator == 0);
it--;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.end();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
it--;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.end();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
it--;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
SECTION("pre-decrement")
{
SECTION("null")
{
json j(json::value_t::null);
json::iterator it = j.end();
CHECK(it.m_it.primitive_iterator == 1);
}
SECTION("number")
{
json j(17);
json::iterator it = j.end();
CHECK(it.m_it.primitive_iterator == 1);
--it;
CHECK(it.m_it.primitive_iterator == 0);
--it;
CHECK((it.m_it.primitive_iterator != 0 and it.m_it.primitive_iterator != 1));
}
SECTION("object")
{
json j({{"foo", "bar"}});
json::iterator it = j.end();
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->end());
--it;
CHECK(it.m_it.object_iterator == it.m_object->m_value.object->begin());
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.end();
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
--it;
CHECK(it.m_it.array_iterator == it.m_object->m_value.array->begin());
CHECK(it.m_it.array_iterator != it.m_object->m_value.array->end());
}
}
}
}

View File

@ -0,0 +1,155 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
TEST_CASE("lexer class")
{
SECTION("scan")
{
SECTION("structural characters")
{
CHECK(json::lexer("[").scan() == json::lexer::token_type::begin_array);
CHECK(json::lexer("]").scan() == json::lexer::token_type::end_array);
CHECK(json::lexer("{").scan() == json::lexer::token_type::begin_object);
CHECK(json::lexer("}").scan() == json::lexer::token_type::end_object);
CHECK(json::lexer(",").scan() == json::lexer::token_type::value_separator);
CHECK(json::lexer(":").scan() == json::lexer::token_type::name_separator);
}
SECTION("literal names")
{
CHECK(json::lexer("null").scan() == json::lexer::token_type::literal_null);
CHECK(json::lexer("true").scan() == json::lexer::token_type::literal_true);
CHECK(json::lexer("false").scan() == json::lexer::token_type::literal_false);
}
SECTION("numbers")
{
CHECK(json::lexer("0").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("1").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("2").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("3").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("4").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("5").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("6").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("7").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("8").scan() == json::lexer::token_type::value_number);
CHECK(json::lexer("9").scan() == json::lexer::token_type::value_number);
}
SECTION("whitespace")
{
// result is end_of_input, because not token is following
CHECK(json::lexer(" ").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer("\t").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer("\n").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer("\r").scan() == json::lexer::token_type::end_of_input);
CHECK(json::lexer(" \t\n\r\n\t ").scan() == json::lexer::token_type::end_of_input);
}
}
SECTION("token_type_name")
{
CHECK(json::lexer::token_type_name(json::lexer::token_type::uninitialized) == "<uninitialized>");
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_true) == "true literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_false) == "false literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::literal_null) == "null literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_string) == "string literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_number) == "number literal");
CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_array) == "'['");
CHECK(json::lexer::token_type_name(json::lexer::token_type::begin_object) == "'{'");
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_array) == "']'");
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_object) == "'}'");
CHECK(json::lexer::token_type_name(json::lexer::token_type::name_separator) == "':'");
CHECK(json::lexer::token_type_name(json::lexer::token_type::value_separator) == "','");
CHECK(json::lexer::token_type_name(json::lexer::token_type::parse_error) == "<parse error>");
CHECK(json::lexer::token_type_name(json::lexer::token_type::end_of_input) == "end of input");
}
SECTION("parse errors on first character")
{
for (int c = 1; c < 128; ++c)
{
auto s = std::string(1, c);
switch (c)
{
// single characters that are valid tokens
case ('['):
case (']'):
case ('{'):
case ('}'):
case (','):
case (':'):
case ('0'):
case ('1'):
case ('2'):
case ('3'):
case ('4'):
case ('5'):
case ('6'):
case ('7'):
case ('8'):
case ('9'):
{
CHECK(json::lexer(s.c_str()).scan() != json::lexer::token_type::parse_error);
break;
}
// whitespace
case (' '):
case ('\t'):
case ('\n'):
case ('\r'):
{
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::end_of_input);
break;
}
// anything else is not expected
default:
{
CHECK(json::lexer(s.c_str()).scan() == json::lexer::token_type::parse_error);
break;
}
}
}
}
SECTION("to_unicode")
{
CHECK(json::lexer::to_unicode(0x1F4A9) == "💩");
CHECK_THROWS_AS(json::lexer::to_unicode(0x200000), std::out_of_range);
CHECK_THROWS_WITH(json::lexer::to_unicode(0x200000), "code points above 0x10FFFF are invalid");
}
}

View File

@ -0,0 +1,765 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
TEST_CASE("parser class")
{
SECTION("parse")
{
SECTION("null")
{
CHECK(json::parser("null").parse() == json(nullptr));
}
SECTION("true")
{
CHECK(json::parser("true").parse() == json(true));
}
SECTION("false")
{
CHECK(json::parser("false").parse() == json(false));
}
SECTION("array")
{
SECTION("empty array")
{
CHECK(json::parser("[]").parse() == json(json::value_t::array));
CHECK(json::parser("[ ]").parse() == json(json::value_t::array));
}
SECTION("nonempty array")
{
CHECK(json::parser("[true, false, null]").parse() == json({true, false, nullptr}));
}
}
SECTION("object")
{
SECTION("empty object")
{
CHECK(json::parser("{}").parse() == json(json::value_t::object));
CHECK(json::parser("{ }").parse() == json(json::value_t::object));
}
SECTION("nonempty object")
{
CHECK(json::parser("{\"\": true, \"one\": 1, \"two\": null}").parse() == json({{"", true}, {"one", 1}, {"two", nullptr}}));
}
}
SECTION("string")
{
// empty string
CHECK(json::parser("\"\"").parse() == json(json::value_t::string));
SECTION("errors")
{
// error: tab in string
CHECK_THROWS_AS(json::parser("\"\t\"").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("\"\t\"").parse(), "parse error - unexpected '\"'");
// error: newline in string
CHECK_THROWS_AS(json::parser("\"\n\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\r\"").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("\"\n\"").parse(), "parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\r\"").parse(), "parse error - unexpected '\"'");
// error: backspace in string
CHECK_THROWS_AS(json::parser("\"\b\"").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'");
// improve code coverage
CHECK_THROWS_AS(json::parser("\uFF01").parse(), std::invalid_argument);
// unescaped control characters
CHECK_THROWS_AS(json::parser("\"\x00\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x01\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x02\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x03\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x04\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x05\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x06\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x07\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x08\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x09\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0a\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0b\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0c\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0d\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0e\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0f\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x10\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x11\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x12\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x13\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x14\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x15\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x16\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x17\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x18\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x19\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1a\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1b\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1c\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1d\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1e\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1f\"").parse(), std::invalid_argument);
}
SECTION("escaped")
{
// quotation mark "\""
auto r1 = R"("\"")"_json;
CHECK(json::parser("\"\\\"\"").parse() == r1);
// reverse solidus "\\"
auto r2 = R"("\\")"_json;
CHECK(json::parser("\"\\\\\"").parse() == r2);
// solidus
CHECK(json::parser("\"\\/\"").parse() == R"("/")"_json);
// backspace
CHECK(json::parser("\"\\b\"").parse() == json("\b"));
// formfeed
CHECK(json::parser("\"\\f\"").parse() == json("\f"));
// newline
CHECK(json::parser("\"\\n\"").parse() == json("\n"));
// carriage return
CHECK(json::parser("\"\\r\"").parse() == json("\r"));
// horizontal tab
CHECK(json::parser("\"\\t\"").parse() == json("\t"));
CHECK(json::parser("\"\\u0001\"").parse().get<json::string_t>() == "\x01");
CHECK(json::parser("\"\\u000a\"").parse().get<json::string_t>() == "\n");
CHECK(json::parser("\"\\u00b0\"").parse().get<json::string_t>() == "°");
CHECK(json::parser("\"\\u0c00\"").parse().get<json::string_t>() == "");
CHECK(json::parser("\"\\ud000\"").parse().get<json::string_t>() == "퀀");
CHECK(json::parser("\"\\u000E\"").parse().get<json::string_t>() == "\x0E");
CHECK(json::parser("\"\\u00F0\"").parse().get<json::string_t>() == "ð");
CHECK(json::parser("\"\\u0100\"").parse().get<json::string_t>() == "Ā");
CHECK(json::parser("\"\\u2000\"").parse().get<json::string_t>() == " ");
CHECK(json::parser("\"\\uFFFF\"").parse().get<json::string_t>() == "￿");
CHECK(json::parser("\"\\u20AC\"").parse().get<json::string_t>() == "");
CHECK(json::parser("\"\"").parse().get<json::string_t>() == "");
CHECK(json::parser("\"🎈\"").parse().get<json::string_t>() == "🎈");
CHECK(json::parse("\"\\ud80c\\udc60\"").get<json::string_t>() == u8"\U00013060");
CHECK(json::parse("\"\\ud83c\\udf1e\"").get<json::string_t>() == "🌞");
}
}
SECTION("number")
{
SECTION("integers")
{
SECTION("without exponent")
{
CHECK(json::parser("-128").parse() == json(-128));
CHECK(json::parser("-0").parse() == json(-0));
CHECK(json::parser("0").parse() == json(0));
CHECK(json::parser("128").parse() == json(128));
}
SECTION("with exponent")
{
CHECK(json::parser("0e1").parse() == json(0e1));
CHECK(json::parser("0E1").parse() == json(0e1));
CHECK(json::parser("10000E-4").parse() == json(10000e-4));
CHECK(json::parser("10000E-3").parse() == json(10000e-3));
CHECK(json::parser("10000E-2").parse() == json(10000e-2));
CHECK(json::parser("10000E-1").parse() == json(10000e-1));
CHECK(json::parser("10000E0").parse() == json(10000e0));
CHECK(json::parser("10000E1").parse() == json(10000e1));
CHECK(json::parser("10000E2").parse() == json(10000e2));
CHECK(json::parser("10000E3").parse() == json(10000e3));
CHECK(json::parser("10000E4").parse() == json(10000e4));
CHECK(json::parser("10000e-4").parse() == json(10000e-4));
CHECK(json::parser("10000e-3").parse() == json(10000e-3));
CHECK(json::parser("10000e-2").parse() == json(10000e-2));
CHECK(json::parser("10000e-1").parse() == json(10000e-1));
CHECK(json::parser("10000e0").parse() == json(10000e0));
CHECK(json::parser("10000e1").parse() == json(10000e1));
CHECK(json::parser("10000e2").parse() == json(10000e2));
CHECK(json::parser("10000e3").parse() == json(10000e3));
CHECK(json::parser("10000e4").parse() == json(10000e4));
CHECK(json::parser("-0e1").parse() == json(-0e1));
CHECK(json::parser("-0E1").parse() == json(-0e1));
CHECK(json::parser("-0E123").parse() == json(-0e123));
}
SECTION("edge cases")
{
// From RFC7159, Section 6:
// Note that when such software is used, numbers that are
// integers and are in the range [-(2**53)+1, (2**53)-1]
// are interoperable in the sense that implementations will
// agree exactly on their numeric values.
// -(2**53)+1
CHECK(json::parser("-9007199254740991").parse().get<int64_t>() == -9007199254740991);
// (2**53)-1
CHECK(json::parser("9007199254740991").parse().get<int64_t>() == 9007199254740991);
}
SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers)
{
// While RFC7159, Section 6 specifies a preference for support
// for ranges in range of IEEE 754-2008 binary64 (double precision)
// this does not accommodate 64 bit integers without loss of accuracy.
// As 64 bit integers are now widely used in software, it is desirable
// to expand support to to the full 64 bit (signed and unsigned) range
// i.e. -(2**63) -> (2**64)-1.
// -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1))
CHECK(json::parser("-9223372036854775808").parse().get<int64_t>() == -9223372036854775807 - 1);
// (2**63)-1
CHECK(json::parser("9223372036854775807").parse().get<int64_t>() == 9223372036854775807);
// (2**64)-1
CHECK(json::parser("18446744073709551615").parse().get<uint64_t>() == 18446744073709551615u);
}
}
SECTION("floating-point")
{
SECTION("without exponent")
{
CHECK(json::parser("-128.5").parse() == json(-128.5));
CHECK(json::parser("0.999").parse() == json(0.999));
CHECK(json::parser("128.5").parse() == json(128.5));
CHECK(json::parser("-0.0").parse() == json(-0.0));
}
SECTION("with exponent")
{
CHECK(json::parser("-128.5E3").parse() == json(-128.5E3));
CHECK(json::parser("-128.5E-3").parse() == json(-128.5E-3));
CHECK(json::parser("-0.0e1").parse() == json(-0.0e1));
CHECK(json::parser("-0.0E1").parse() == json(-0.0e1));
}
}
SECTION("invalid numbers")
{
CHECK_THROWS_AS(json::parser("01").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("--1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E-").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1.E1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-1E").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0E#").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0E-#").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0#").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.0:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.0Z").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0E123:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0e0-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0e-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0f").parse(), std::invalid_argument);
// numbers must not begin with "+"
CHECK_THROWS_AS(json::parser("+1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("+0").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("01").parse(),
"parse error - unexpected number literal; expected end of input");
CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("1.").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E-").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("1.E1").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("-1E").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0E#").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0E-#").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0#").parse(),
"parse error - unexpected '#'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0.0:").parse(),
"parse error - unexpected ':'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0.0Z").parse(),
"parse error - unexpected 'Z'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0E123:").parse(),
"parse error - unexpected ':'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0e0-:").parse(),
"parse error - unexpected '-'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0e-:").parse(),
"parse error - unexpected 'e'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0f").parse(),
"parse error - unexpected 'f'; expected end of input");
}
}
}
SECTION("parse errors")
{
// unexpected end of number
CHECK_THROWS_AS(json::parser("0.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("0.").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("--").parse(),
"parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("-0.").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("-.").parse(),
"parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("-:").parse(),
"parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("0.:").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("e.").parse(),
"parse error - unexpected 'e'");
CHECK_THROWS_WITH(json::parser("1e.").parse(),
"parse error - unexpected 'e'; expected end of input");
CHECK_THROWS_WITH(json::parser("1e/").parse(),
"parse error - unexpected 'e'; expected end of input");
CHECK_THROWS_WITH(json::parser("1e:").parse(),
"parse error - unexpected 'e'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E.").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E/").parse(),
"parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E:").parse(),
"parse error - unexpected 'E'; expected end of input");
// unexpected end of null
CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("nu").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("nul").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("n").parse(), "parse error - unexpected 'n'");
CHECK_THROWS_WITH(json::parser("nu").parse(),
"parse error - unexpected 'n'");
CHECK_THROWS_WITH(json::parser("nul").parse(),
"parse error - unexpected 'n'");
// unexpected end of true
CHECK_THROWS_AS(json::parser("t").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("tr").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("tru").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("t").parse(), "parse error - unexpected 't'");
CHECK_THROWS_WITH(json::parser("tr").parse(),
"parse error - unexpected 't'");
CHECK_THROWS_WITH(json::parser("tru").parse(),
"parse error - unexpected 't'");
// unexpected end of false
CHECK_THROWS_AS(json::parser("f").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("fa").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("fal").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("fals").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("f").parse(), "parse error - unexpected 'f'");
CHECK_THROWS_WITH(json::parser("fa").parse(),
"parse error - unexpected 'f'");
CHECK_THROWS_WITH(json::parser("fal").parse(),
"parse error - unexpected 'f'");
CHECK_THROWS_WITH(json::parser("fals").parse(),
"parse error - unexpected 'f'");
// missing/unexpected end of array
CHECK_THROWS_AS(json::parser("[").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("[1").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("[1,").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("[1,]").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("]").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("[").parse(),
"parse error - unexpected end of input");
CHECK_THROWS_WITH(json::parser("[1").parse(),
"parse error - unexpected end of input; expected ']'");
CHECK_THROWS_WITH(json::parser("[1,").parse(),
"parse error - unexpected end of input");
CHECK_THROWS_WITH(json::parser("[1,]").parse(),
"parse error - unexpected ']'");
CHECK_THROWS_WITH(json::parser("]").parse(), "parse error - unexpected ']'");
// missing/unexpected end of object
CHECK_THROWS_AS(json::parser("{").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\":").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\":}").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("{\"foo\":1,}").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("}").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("{").parse(),
"parse error - unexpected end of input; expected string literal");
CHECK_THROWS_WITH(json::parser("{\"foo\"").parse(),
"parse error - unexpected end of input; expected ':'");
CHECK_THROWS_WITH(json::parser("{\"foo\":").parse(),
"parse error - unexpected end of input");
CHECK_THROWS_WITH(json::parser("{\"foo\":}").parse(),
"parse error - unexpected '}'");
CHECK_THROWS_WITH(json::parser("{\"foo\":1,}").parse(),
"parse error - unexpected '}'; expected string literal");
CHECK_THROWS_WITH(json::parser("}").parse(), "parse error - unexpected '}'");
// missing/unexpected end of string
CHECK_THROWS_AS(json::parser("\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u0\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u01\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u012\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u0").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u01").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\\u012").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("\"").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\\"").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u\"").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u0\"").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u01\"").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u012\"").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u0").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u01").parse(),
"parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser("\"\\u012").parse(),
"parse error - unexpected '\"'");
// invalid escapes
for (int c = 1; c < 128; ++c)
{
auto s = std::string("\"\\") + std::string(1, c) + "\"";
switch (c)
{
// valid escapes
case ('"'):
case ('\\'):
case ('/'):
case ('b'):
case ('f'):
case ('n'):
case ('r'):
case ('t'):
{
CHECK_NOTHROW(json::parser(s).parse());
break;
}
// \u must be followed with four numbers, so we skip it here
case ('u'):
{
break;
}
// any other combination of backslash and character is invalid
default:
{
CHECK_THROWS_AS(json::parser(s).parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser(s).parse(), "parse error - unexpected '\"'");
break;
}
}
}
// invalid \uxxxx escapes
{
// check whether character is a valid hex character
const auto valid = [](int c)
{
switch (c)
{
case ('0'):
case ('1'):
case ('2'):
case ('3'):
case ('4'):
case ('5'):
case ('6'):
case ('7'):
case ('8'):
case ('9'):
case ('a'):
case ('b'):
case ('c'):
case ('d'):
case ('e'):
case ('f'):
case ('A'):
case ('B'):
case ('C'):
case ('D'):
case ('E'):
case ('F'):
{
return true;
}
default:
{
return false;
}
}
};
for (int c = 1; c < 128; ++c)
{
std::string s = "\"\\u";
// create a string with the iterated character at each position
auto s1 = s + "000" + std::string(1, c) + "\"";
auto s2 = s + "00" + std::string(1, c) + "0\"";
auto s3 = s + "0" + std::string(1, c) + "00\"";
auto s4 = s + std::string(1, c) + "000\"";
if (valid(c))
{
CHECK_NOTHROW(json::parser(s1).parse());
CHECK_NOTHROW(json::parser(s2).parse());
CHECK_NOTHROW(json::parser(s3).parse());
CHECK_NOTHROW(json::parser(s4).parse());
}
else
{
CHECK_THROWS_AS(json::parser(s1).parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser(s2).parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser(s3).parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser(s4).parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser(s1).parse(), "parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser(s2).parse(), "parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser(s3).parse(), "parse error - unexpected '\"'");
CHECK_THROWS_WITH(json::parser(s4).parse(), "parse error - unexpected '\"'");
}
}
}
// missing part of a surrogate pair
CHECK_THROWS_AS(json::parse("\"\\uD80C\""), std::invalid_argument);
CHECK_THROWS_WITH(json::parse("\"\\uD80C\""), "missing low surrogate");
// invalid surrogate pair
CHECK_THROWS_AS(json::parse("\"\\uD80C\\uD80C\""), std::invalid_argument);
CHECK_THROWS_AS(json::parse("\"\\uD80C\\u0000\""), std::invalid_argument);
CHECK_THROWS_AS(json::parse("\"\\uD80C\\uFFFF\""), std::invalid_argument);
CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uD80C\""),
"missing or wrong low surrogate");
CHECK_THROWS_WITH(json::parse("\"\\uD80C\\u0000\""),
"missing or wrong low surrogate");
CHECK_THROWS_WITH(json::parse("\"\\uD80C\\uFFFF\""),
"missing or wrong low surrogate");
}
SECTION("callback function")
{
auto s_object = R"(
{
"foo": 2,
"bar": {
"baz": 1
}
}
)";
auto s_array = R"(
[1,2,[3,4,5],4,5]
)";
SECTION("filter nothing")
{
json j_object = json::parse(s_object, [](int, json::parse_event_t, const json&)
{
return true;
});
CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}}));
json j_array = json::parse(s_array, [](int, json::parse_event_t, const json&)
{
return true;
});
CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5}));
}
SECTION("filter everything")
{
json j_object = json::parse(s_object, [](int, json::parse_event_t, const json&)
{
return false;
});
// the top-level object will be discarded, leaving a null
CHECK (j_object.is_null());
json j_array = json::parse(s_array, [](int, json::parse_event_t, const json&)
{
return false;
});
// the top-level array will be discarded, leaving a null
CHECK (j_array.is_null());
}
SECTION("filter specific element")
{
json j_object = json::parse(s_object, [](int, json::parse_event_t, const json & j)
{
// filter all number(2) elements
if (j == json(2))
{
return false;
}
else
{
return true;
}
});
CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
json j_array = json::parse(s_array, [](int, json::parse_event_t, const json & j)
{
if (j == json(2))
{
return false;
}
else
{
return true;
}
});
CHECK (j_array == json({1, {3, 4, 5}, 4, 5}));
}
SECTION("filter specific events")
{
SECTION("first closing event")
{
{
json j_object = json::parse(s_object, [](int, json::parse_event_t e, const json&)
{
static bool first = true;
if (e == json::parse_event_t::object_end and first)
{
first = false;
return false;
}
else
{
return true;
}
});
// the first completed object will be discarded
CHECK (j_object == json({{"foo", 2}}));
}
{
json j_array = json::parse(s_array, [](int, json::parse_event_t e, const json&)
{
static bool first = true;
if (e == json::parse_event_t::array_end and first)
{
first = false;
return false;
}
else
{
return true;
}
});
// the first completed array will be discarded
CHECK (j_array == json({1, 2, 4, 5}));
}
}
}
SECTION("special cases")
{
// the following test cases cover the situation in which an empty
// object and array is discarded only after the closing character
// has been read
json j_empty_object = json::parse("{}", [](int, json::parse_event_t e, const json&)
{
if (e == json::parse_event_t::object_end)
{
return false;
}
else
{
return true;
}
});
CHECK(j_empty_object == json());
json j_empty_array = json::parse("[]", [](int, json::parse_event_t e, const json&)
{
if (e == json::parse_event_t::array_end)
{
return false;
}
else
{
return true;
}
});
CHECK(j_empty_array == json());
}
}
SECTION("copy constructor")
{
json::string_t* s = new json::string_t("[1,2,3,4]");
json::parser p(*s);
delete s;
CHECK(p.parse() == json({1, 2, 3, 4}));
}
}

View File

@ -0,0 +1,246 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("lexicographical comparison operators")
{
SECTION("types")
{
std::vector<json::value_t> j_types =
{
json::value_t::null,
json::value_t::boolean,
json::value_t::number_integer,
json::value_t::number_unsigned,
json::value_t::number_float,
json::value_t::object,
json::value_t::array,
json::value_t::string
};
SECTION("comparison: less")
{
std::vector<std::vector<bool>> expected =
{
{false, true, true, true, true, true, true, true},
{false, false, true, true, true, true, true, true},
{false, false, false, false, false, true, true, true},
{false, false, false, false, false, true, true, true},
{false, false, false, false, false, true, true, true},
{false, false, false, false, false, false, true, true},
{false, false, false, false, false, false, false, true},
{false, false, false, false, false, false, false, false}
};
for (size_t i = 0; i < j_types.size(); ++i)
{
for (size_t j = 0; j < j_types.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check precomputed values
CHECK(operator<(j_types[i], j_types[j]) == expected[i][j]);
}
}
}
}
SECTION("values")
{
json j_values =
{
nullptr, nullptr,
17, 42,
8u, 13u,
3.14159, 23.42,
"foo", "bar",
true, false,
{1, 2, 3}, {"one", "two", "three"},
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}
};
SECTION("comparison: equal")
{
std::vector<std::vector<bool>> expected =
{
{true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}
};
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check precomputed values
CHECK( (j_values[i] == j_values[j]) == expected[i][j] );
}
}
// comparison with discarded elements
json j_discarded(json::value_t::discarded);
for (size_t i = 0; i < j_values.size(); ++i)
{
CHECK( (j_values[i] == j_discarded) == false);
CHECK( (j_discarded == j_values[i]) == false);
CHECK( (j_discarded == j_discarded) == false);
}
// compare with null pointer
json j_null;
CHECK(j_null == nullptr);
CHECK(nullptr == j_null);
}
SECTION("comparison: not equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check definition
CHECK( (j_values[i] != j_values[j]) == not(j_values[i] == j_values[j]) );
}
}
// compare with null pointer
json j_null;
CHECK( (j_null != nullptr) == false);
CHECK( (nullptr != j_null) == false);
CHECK( (j_null != nullptr) == not(j_null == nullptr));
CHECK( (nullptr != j_null) == not(nullptr == j_null));
}
SECTION("comparison: less")
{
std::vector<std::vector<bool>> expected =
{
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
{false, false, false, true, false, false, false, true, true, true, false, false, true, true, true, true},
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, true},
{false, false, true, true, false, true, false, true, true, true, false, false, true, true, true, true},
{false, false, true, true, false, false, false, true, true, true, false, false, true, true, true, true},
{false, false, true, true, true, true, false, true, true, true, false, false, true, true, true, true},
{false, false, false, true, false, false, false, false, true, true, false, false, true, true, true, true},
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
{false, false, true, true, true, true, true, true, true, true, false, false, true, true, true, true},
{false, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true},
{false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, false},
{false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false},
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false},
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, false}
};
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check precomputed values
CHECK( (j_values[i] < j_values[j]) == expected[i][j] );
}
}
// comparison with discarded elements
json j_discarded(json::value_t::discarded);
for (size_t i = 0; i < j_values.size(); ++i)
{
CAPTURE(i);
CHECK( (j_values[i] < j_discarded) == false);
CHECK( (j_discarded < j_values[i]) == false);
CHECK( (j_discarded < j_discarded) == false);
}
}
SECTION("comparison: less than or equal equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check definition
CHECK( (j_values[i] <= j_values[j]) == not(j_values[j] < j_values[i]) );
}
}
}
SECTION("comparison: greater than")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check definition
CHECK( (j_values[i] > j_values[j]) == (j_values[j] < j_values[i]) );
}
}
}
SECTION("comparison: greater than or equal")
{
for (size_t i = 0; i < j_values.size(); ++i)
{
for (size_t j = 0; j < j_values.size(); ++j)
{
CAPTURE(i);
CAPTURE(j);
// check definition
CHECK( (j_values[i] >= j_values[j]) == not(j_values[i] < j_values[j]) );
}
}
}
}
}

169
test/src/unit-concepts.cpp Normal file
View File

@ -0,0 +1,169 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("concepts")
{
SECTION("container requirements for json")
{
// X: container class: json
// T: type of objects: json
// a, b: values of type X: json
// TABLE 96 - Container Requirements
// X::value_type must return T
CHECK((std::is_same<json::value_type, json>::value));
// X::reference must return lvalue of T
CHECK((std::is_same<json::reference, json&>::value));
// X::const_reference must return const lvalue of T
CHECK((std::is_same<json::const_reference, const json&>::value));
// X::iterator must return iterator whose value_type is T
CHECK((std::is_same<json::iterator::value_type, json>::value));
// X::iterator must meet the forward iterator requirements
CHECK((std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<json::iterator>::iterator_category>::value));
// X::iterator must be convertible to X::const_iterator
CHECK((std::is_convertible<json::iterator, json::const_iterator>::value));
// X::const_iterator must return iterator whose value_type is T
CHECK((std::is_same<json::const_iterator::value_type, json>::value));
// X::const_iterator must meet the forward iterator requirements
CHECK((std::is_base_of<std::forward_iterator_tag, typename std::iterator_traits<json::const_iterator>::iterator_category>::value));
// X::difference_type must return a signed integer
CHECK((std::is_signed<json::difference_type>::value));
// X::difference_type must be identical to X::iterator::difference_type
CHECK((std::is_same<json::difference_type, json::iterator::difference_type>::value));
// X::difference_type must be identical to X::const_iterator::difference_type
CHECK((std::is_same<json::difference_type, json::const_iterator::difference_type>::value));
// X::size_type must return an unsigned integer
CHECK((std::is_unsigned<json::size_type>::value));
// X::size_type can represent any non-negative value of X::difference_type
CHECK(std::numeric_limits<json::difference_type>::max() <=
std::numeric_limits<json::size_type>::max());
// the expression "X u" has the post-condition "u.empty()"
{
json u;
CHECK(u.empty());
}
// the expression "X()" has the post-condition "X().empty()"
CHECK(json().empty());
}
SECTION("class json")
{
SECTION("DefaultConstructible")
{
CHECK(std::is_nothrow_default_constructible<json>::value);
}
SECTION("MoveConstructible")
{
CHECK(std::is_nothrow_move_constructible<json>::value);
}
SECTION("CopyConstructible")
{
CHECK(std::is_copy_constructible<json>::value);
}
SECTION("MoveAssignable")
{
CHECK(std::is_nothrow_move_assignable<json>::value);
}
SECTION("CopyAssignable")
{
CHECK(std::is_copy_assignable<json>::value);
}
SECTION("Destructible")
{
CHECK(std::is_nothrow_destructible<json>::value);
}
SECTION("StandardLayoutType")
{
CHECK(std::is_standard_layout<json>::value);
}
}
SECTION("class iterator")
{
SECTION("CopyConstructible")
{
CHECK(std::is_nothrow_copy_constructible<json::iterator>::value);
CHECK(std::is_nothrow_copy_constructible<json::const_iterator>::value);
}
SECTION("CopyAssignable")
{
// STL iterators used by json::iterator don't pass this test in Debug mode
#if !defined(_MSC_VER) || (_ITERATOR_DEBUG_LEVEL == 0)
CHECK(std::is_nothrow_copy_assignable<json::iterator>::value);
CHECK(std::is_nothrow_copy_assignable<json::const_iterator>::value);
#endif
}
SECTION("Destructible")
{
CHECK(std::is_nothrow_destructible<json::iterator>::value);
CHECK(std::is_nothrow_destructible<json::const_iterator>::value);
}
SECTION("Swappable")
{
{
json j {1, 2, 3};
json::iterator it1 = j.begin();
json::iterator it2 = j.end();
std::swap(it1, it2);
CHECK(it1 == j.end());
CHECK(it2 == j.begin());
}
{
json j {1, 2, 3};
json::const_iterator it1 = j.cbegin();
json::const_iterator it2 = j.cend();
std::swap(it1, it2);
CHECK(it1 == j.end());
CHECK(it2 == j.begin());
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,191 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("other constructors and destructor")
{
SECTION("copy constructor")
{
SECTION("object")
{
json j {{"foo", 1}, {"bar", false}};
json k(j);
CHECK(j == k);
}
SECTION("array")
{
json j {"foo", 1, 42.23, false};
json k(j);
CHECK(j == k);
}
SECTION("null")
{
json j(nullptr);
json k(j);
CHECK(j == k);
}
SECTION("boolean")
{
json j(true);
json k(j);
CHECK(j == k);
}
SECTION("string")
{
json j("Hello world");
json k(j);
CHECK(j == k);
}
SECTION("number (integer)")
{
json j(42);
json k(j);
CHECK(j == k);
}
SECTION("number (unsigned)")
{
json j(42u);
json k(j);
CHECK(j == k);
}
SECTION("number (floating-point)")
{
json j(42.23);
json k(j);
CHECK(j == k);
}
}
SECTION("move constructor")
{
json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}};
CHECK(j.type() == json::value_t::object);
json k(std::move(j));
CHECK(k.type() == json::value_t::object);
CHECK(j.type() == json::value_t::null);
}
SECTION("copy assignment")
{
SECTION("object")
{
json j {{"foo", 1}, {"bar", false}};
json k;
k = j;
CHECK(j == k);
}
SECTION("array")
{
json j {"foo", 1, 42.23, false};
json k;
k = j;
CHECK(j == k);
}
SECTION("null")
{
json j(nullptr);
json k;
k = j;
CHECK(j == k);
}
SECTION("boolean")
{
json j(true);
json k;
k = j;
CHECK(j == k);
}
SECTION("string")
{
json j("Hello world");
json k;
k = j;
CHECK(j == k);
}
SECTION("number (integer)")
{
json j(42);
json k;
k = j;
CHECK(j == k);
}
SECTION("number (unsigned)")
{
json j(42u);
json k;
k = j;
CHECK(j == k);
}
SECTION("number (floating-point)")
{
json j(42.23);
json k;
k = j;
CHECK(j == k);
}
}
SECTION("destructor")
{
SECTION("object")
{
auto j = new json {{"foo", 1}, {"bar", false}};
delete j;
}
SECTION("array")
{
auto j = new json {"foo", 1, 1u, false, 23.42};
delete j;
}
SECTION("string")
{
auto j = new json("Hello world");
delete j;
}
}
}

View File

@ -0,0 +1,92 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
TEST_CASE("convenience functions")
{
SECTION("type name as string")
{
CHECK(json(json::value_t::null).type_name() == "null");
CHECK(json(json::value_t::object).type_name() == "object");
CHECK(json(json::value_t::array).type_name() == "array");
CHECK(json(json::value_t::number_integer).type_name() == "number");
CHECK(json(json::value_t::number_unsigned).type_name() == "number");
CHECK(json(json::value_t::number_float).type_name() == "number");
CHECK(json(json::value_t::boolean).type_name() == "boolean");
CHECK(json(json::value_t::string).type_name() == "string");
CHECK(json(json::value_t::discarded).type_name() == "discarded");
}
SECTION("string escape")
{
CHECK(json::escape_string("\"") == "\\\"");
CHECK(json::escape_string("\\") == "\\\\");
CHECK(json::escape_string("\b") == "\\b");
CHECK(json::escape_string("\f") == "\\f");
CHECK(json::escape_string("\n") == "\\n");
CHECK(json::escape_string("\r") == "\\r");
CHECK(json::escape_string("\t") == "\\t");
CHECK(json::escape_string("\x01") == "\\u0001");
CHECK(json::escape_string("\x02") == "\\u0002");
CHECK(json::escape_string("\x03") == "\\u0003");
CHECK(json::escape_string("\x04") == "\\u0004");
CHECK(json::escape_string("\x05") == "\\u0005");
CHECK(json::escape_string("\x06") == "\\u0006");
CHECK(json::escape_string("\x07") == "\\u0007");
CHECK(json::escape_string("\x08") == "\\b");
CHECK(json::escape_string("\x09") == "\\t");
CHECK(json::escape_string("\x0a") == "\\n");
CHECK(json::escape_string("\x0b") == "\\u000b");
CHECK(json::escape_string("\x0c") == "\\f");
CHECK(json::escape_string("\x0d") == "\\r");
CHECK(json::escape_string("\x0e") == "\\u000e");
CHECK(json::escape_string("\x0f") == "\\u000f");
CHECK(json::escape_string("\x10") == "\\u0010");
CHECK(json::escape_string("\x11") == "\\u0011");
CHECK(json::escape_string("\x12") == "\\u0012");
CHECK(json::escape_string("\x13") == "\\u0013");
CHECK(json::escape_string("\x14") == "\\u0014");
CHECK(json::escape_string("\x15") == "\\u0015");
CHECK(json::escape_string("\x16") == "\\u0016");
CHECK(json::escape_string("\x17") == "\\u0017");
CHECK(json::escape_string("\x18") == "\\u0018");
CHECK(json::escape_string("\x19") == "\\u0019");
CHECK(json::escape_string("\x1a") == "\\u001a");
CHECK(json::escape_string("\x1b") == "\\u001b");
CHECK(json::escape_string("\x1c") == "\\u001c");
CHECK(json::escape_string("\x1d") == "\\u001d");
CHECK(json::escape_string("\x1e") == "\\u001e");
CHECK(json::escape_string("\x1f") == "\\u001f");
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("deserialization")
{
SECTION("stream")
{
std::stringstream ss;
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(ss);
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("string")
{
auto s = "[\"foo\",1,2,3,false,{\"one\":1}]";
json j = json::parse(s);
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("operator<<")
{
std::stringstream ss;
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j;
j << ss;
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("operator>>")
{
std::stringstream ss;
ss << "[\"foo\",1,2,3,false,{\"one\":1}]";
json j;
ss >> j;
CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
SECTION("user-defined string literal")
{
CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}}));
}
}

View File

@ -0,0 +1,947 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("element access 1")
{
SECTION("array")
{
json j = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
const json j_const = j;
SECTION("access specified element with bounds checking")
{
SECTION("access within bounds")
{
CHECK(j.at(0) == json(1));
CHECK(j.at(1) == json(1u));
CHECK(j.at(2) == json(true));
CHECK(j.at(3) == json(nullptr));
CHECK(j.at(4) == json("string"));
CHECK(j.at(5) == json(42.23));
CHECK(j.at(6) == json(json::object()));
CHECK(j.at(7) == json({1, 2, 3}));
CHECK(j_const.at(0) == json(1));
CHECK(j_const.at(1) == json(1u));
CHECK(j_const.at(2) == json(true));
CHECK(j_const.at(3) == json(nullptr));
CHECK(j_const.at(4) == json("string"));
CHECK(j_const.at(5) == json(42.23));
CHECK(j_const.at(6) == json(json::object()));
CHECK(j_const.at(7) == json({1, 2, 3}));
}
SECTION("access outside bounds")
{
CHECK_THROWS_AS(j.at(8), std::out_of_range);
CHECK_THROWS_AS(j_const.at(8), std::out_of_range);
CHECK_THROWS_WITH(j.at(8), "array index 8 is out of range");
CHECK_THROWS_WITH(j_const.at(8), "array index 8 is out of range");
}
SECTION("access on non-array type")
{
SECTION("null")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with null");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with null");
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with boolean");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with boolean");
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with string");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with string");
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with object");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with object");
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number");
}
SECTION("number (unsigned)")
{
json j_nonarray(json::value_t::number_unsigned);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number");
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error);
CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number");
}
}
}
SECTION("front and back")
{
CHECK(j.front() == json(1));
CHECK(j_const.front() == json(1));
CHECK(j.back() == json({1, 2, 3}));
CHECK(j_const.back() == json({1, 2, 3}));
}
SECTION("access specified element")
{
SECTION("access within bounds")
{
CHECK(j[0] == json(1));
CHECK(j[1] == json(1u));
CHECK(j[2] == json(true));
CHECK(j[3] == json(nullptr));
CHECK(j[4] == json("string"));
CHECK(j[5] == json(42.23));
CHECK(j[6] == json(json::object()));
CHECK(j[7] == json({1, 2, 3}));
CHECK(j_const[0] == json(1));
CHECK(j_const[1] == json(1u));
CHECK(j_const[2] == json(true));
CHECK(j_const[3] == json(nullptr));
CHECK(j_const[4] == json("string"));
CHECK(j_const[5] == json(42.23));
CHECK(j_const[6] == json(json::object()));
CHECK(j_const[7] == json({1, 2, 3}));
}
SECTION("access on non-array type")
{
SECTION("null")
{
SECTION("standard tests")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK_NOTHROW(j_nonarray[0]);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with null");
}
SECTION("implicit transformation to properly filled array")
{
json j_nonarray;
j_nonarray[3] = 42;
CHECK(j_nonarray == json({nullptr, nullptr, nullptr, 42}));
}
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::domain_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with boolean");
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with boolean");
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::domain_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with string");
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with string");
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::domain_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with object");
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with object");
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::domain_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number");
}
SECTION("number (unsigned)")
{
json j_nonarray(json::value_t::number_unsigned);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::domain_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number");
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK_THROWS_AS(j_nonarray[0], std::domain_error);
CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error);
CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number");
}
}
}
SECTION("remove specified element")
{
SECTION("remove element by index")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(0);
CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(1);
CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(2);
CHECK(jarray == json({1, 1u, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(3);
CHECK(jarray == json({1, 1u, true, "string", 42.23, json::object(), {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(4);
CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(5);
CHECK(jarray == json({1, 1u, true, nullptr, "string", json::object(), {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(6);
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, {1, 2, 3}}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
jarray.erase(7);
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object()}));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
CHECK_THROWS_AS(jarray.erase(8), std::out_of_range);
CHECK_THROWS_WITH(jarray.erase(8), "array index 8 is out of range");
}
}
SECTION("remove element by iterator")
{
SECTION("erase(begin())")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::iterator it2 = jarray.erase(jarray.begin());
CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
CHECK(*it2 == json(1u));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::const_iterator it2 = jarray.erase(jarray.cbegin());
CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
CHECK(*it2 == json(1u));
}
}
SECTION("erase(begin(), end())")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::iterator it2 = jarray.erase(jarray.begin(), jarray.end());
CHECK(jarray == json::array());
CHECK(it2 == jarray.end());
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cend());
CHECK(jarray == json::array());
CHECK(it2 == jarray.cend());
}
}
SECTION("erase(begin(), begin())")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::iterator it2 = jarray.erase(jarray.begin(), jarray.begin());
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
CHECK(*it2 == json(1));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cbegin());
CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}));
CHECK(*it2 == json(1));
}
}
SECTION("erase at offset")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::iterator it = jarray.begin() + 4;
json::iterator it2 = jarray.erase(it);
CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
CHECK(*it2 == json(42.23));
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::const_iterator it = jarray.cbegin() + 4;
json::const_iterator it2 = jarray.erase(it);
CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}}));
CHECK(*it2 == json(42.23));
}
}
SECTION("erase subrange")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::iterator it2 = jarray.erase(jarray.begin() + 3, jarray.begin() + 6);
CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}}));
CHECK(*it2 == json::object());
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json::const_iterator it2 = jarray.erase(jarray.cbegin() + 3, jarray.cbegin() + 6);
CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}}));
CHECK(*it2 == json::object());
}
}
SECTION("different arrays")
{
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json jarray2 = {"foo", "bar"};
CHECK_THROWS_AS(jarray.erase(jarray2.begin()), std::domain_error);
CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error);
CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray.end()), std::domain_error);
CHECK_THROWS_AS(jarray.erase(jarray2.begin(), jarray2.end()), std::domain_error);
CHECK_THROWS_WITH(jarray.erase(jarray2.begin()), "iterator does not fit current value");
CHECK_THROWS_WITH(jarray.erase(jarray.begin(), jarray2.end()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray.end()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jarray.erase(jarray2.begin(), jarray2.end()),
"iterators do not fit current value");
}
{
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json jarray2 = {"foo", "bar"};
CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), std::domain_error);
CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error);
CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), std::domain_error);
CHECK_THROWS_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), std::domain_error);
CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin()), "iterator does not fit current value");
CHECK_THROWS_WITH(jarray.erase(jarray.cbegin(), jarray2.cend()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray.cend()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jarray.erase(jarray2.cbegin(), jarray2.cend()),
"iterators do not fit current value");
}
}
}
SECTION("remove element by index in non-array type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with string");
}
SECTION("object")
{
json j_nonobject(json::value_t::object);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with object");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number");
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number");
}
}
}
}
SECTION("other values")
{
SECTION("front and back")
{
SECTION("null")
{
{
json j;
CHECK_THROWS_AS(j.front(), std::out_of_range);
CHECK_THROWS_AS(j.back(), std::out_of_range);
CHECK_THROWS_WITH(j.front(), "cannot get value");
CHECK_THROWS_WITH(j.back(), "cannot get value");
}
{
const json j{};
CHECK_THROWS_AS(j.front(), std::out_of_range);
CHECK_THROWS_AS(j.back(), std::out_of_range);
CHECK_THROWS_WITH(j.front(), "cannot get value");
CHECK_THROWS_WITH(j.back(), "cannot get value");
}
}
SECTION("string")
{
{
json j = "foo";
CHECK(j.front() == j);
CHECK(j.back() == j);
}
{
const json j = "bar";
CHECK(j.front() == j);
CHECK(j.back() == j);
}
}
SECTION("number (boolean)")
{
{
json j = false;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
{
const json j = true;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
}
SECTION("number (integer)")
{
{
json j = 17;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
{
const json j = 17;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
}
SECTION("number (unsigned)")
{
{
json j = 17u;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
{
const json j = 17u;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
{
const json j = 23.42;
CHECK(j.front() == j);
CHECK(j.back() == j);
}
}
}
SECTION("erase with one valid iterator")
{
SECTION("null")
{
{
json j;
CHECK_THROWS_AS(j.erase(j.begin()), std::domain_error);
CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null");
}
{
json j;
CHECK_THROWS_AS(j.erase(j.cbegin()), std::domain_error);
CHECK_THROWS_WITH(j.erase(j.begin()), "cannot use erase() with null");
}
}
SECTION("string")
{
{
json j = "foo";
json::iterator it = j.erase(j.begin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = "bar";
json::const_iterator it = j.erase(j.cbegin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (boolean)")
{
{
json j = false;
json::iterator it = j.erase(j.begin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = true;
json::const_iterator it = j.erase(j.cbegin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (integer)")
{
{
json j = 17;
json::iterator it = j.erase(j.begin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = 17;
json::const_iterator it = j.erase(j.cbegin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (unsigned)")
{
{
json j = 17u;
json::iterator it = j.erase(j.begin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = 17u;
json::const_iterator it = j.erase(j.cbegin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
json::iterator it = j.erase(j.begin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = 23.42;
json::const_iterator it = j.erase(j.cbegin());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
}
SECTION("erase with one invalid iterator")
{
SECTION("string")
{
{
json j = "foo";
CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range");
}
{
json j = "bar";
CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range");
}
}
SECTION("number (boolean)")
{
{
json j = false;
CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range");
}
{
json j = true;
CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range");
}
}
SECTION("number (integer)")
{
{
json j = 17;
CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range");
}
{
json j = 17;
CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range");
}
}
SECTION("number (unsigned)")
{
{
json j = 17u;
CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range");
}
{
json j = 17u;
CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range");
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range");
}
{
json j = 23.42;
CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range");
}
}
}
SECTION("erase with two valid iterators")
{
SECTION("null")
{
{
json j;
CHECK_THROWS_AS(j.erase(j.begin(), j.end()), std::domain_error);
CHECK_THROWS_WITH(j.erase(j.begin(), j.end()), "cannot use erase() with null");
}
{
json j;
CHECK_THROWS_AS(j.erase(j.cbegin(), j.cend()), std::domain_error);
CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cend()), "cannot use erase() with null");
}
}
SECTION("string")
{
{
json j = "foo";
json::iterator it = j.erase(j.begin(), j.end());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = "bar";
json::const_iterator it = j.erase(j.cbegin(), j.cend());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (boolean)")
{
{
json j = false;
json::iterator it = j.erase(j.begin(), j.end());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = true;
json::const_iterator it = j.erase(j.cbegin(), j.cend());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (integer)")
{
{
json j = 17;
json::iterator it = j.erase(j.begin(), j.end());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = 17;
json::const_iterator it = j.erase(j.cbegin(), j.cend());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (unsigned)")
{
{
json j = 17u;
json::iterator it = j.erase(j.begin(), j.end());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = 17u;
json::const_iterator it = j.erase(j.cbegin(), j.cend());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
json::iterator it = j.erase(j.begin(), j.end());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
{
json j = 23.42;
json::const_iterator it = j.erase(j.cbegin(), j.cend());
CHECK(j.type() == json::value_t::null);
CHECK(it == j.end());
}
}
}
SECTION("erase with two invalid iterators")
{
SECTION("string")
{
{
json j = "foo";
CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range");
}
{
json j = "bar";
CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range");
}
}
SECTION("number (boolean)")
{
{
json j = false;
CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range");
}
{
json j = true;
CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range");
}
}
SECTION("number (integer)")
{
{
json j = 17;
CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range");
}
{
json j = 17;
CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range");
}
}
SECTION("number (unsigned)")
{
{
json j = 17u;
CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range");
}
{
json j = 17u;
CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range");
}
}
SECTION("number (floating point)")
{
{
json j = 23.42;
CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range");
}
{
json j = 23.42;
CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range);
CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range);
CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range");
CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range");
}
}
}
}
}

View File

@ -0,0 +1,959 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("element access 2")
{
SECTION("object")
{
json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}};
const json j_const = j;
SECTION("access specified element with bounds checking")
{
SECTION("access within bounds")
{
CHECK(j.at("integer") == json(1));
CHECK(j.at("unsigned") == json(1u));
CHECK(j.at("boolean") == json(true));
CHECK(j.at("null") == json(nullptr));
CHECK(j.at("string") == json("hello world"));
CHECK(j.at("floating") == json(42.23));
CHECK(j.at("object") == json(json::object()));
CHECK(j.at("array") == json({1, 2, 3}));
CHECK(j_const.at("integer") == json(1));
CHECK(j_const.at("unsigned") == json(1u));
CHECK(j_const.at("boolean") == json(true));
CHECK(j_const.at("null") == json(nullptr));
CHECK(j_const.at("string") == json("hello world"));
CHECK(j_const.at("floating") == json(42.23));
CHECK(j_const.at("object") == json(json::object()));
CHECK(j_const.at("array") == json({1, 2, 3}));
}
SECTION("access outside bounds")
{
CHECK_THROWS_AS(j.at("foo"), std::out_of_range);
CHECK_THROWS_AS(j_const.at("foo"), std::out_of_range);
CHECK_THROWS_WITH(j.at("foo"), "key 'foo' not found");
CHECK_THROWS_WITH(j_const.at("foo"), "key 'foo' not found");
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with null");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with boolean");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with string");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with string");
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with array");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with array");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
}
}
}
SECTION("access specified element with default value")
{
SECTION("given a key")
{
SECTION("access existing value")
{
CHECK(j.value("integer", 2) == 1);
CHECK(j.value("integer", 1.0) == Approx(1));
CHECK(j.value("unsigned", 2) == 1u);
CHECK(j.value("unsigned", 1.0) == Approx(1u));
CHECK(j.value("null", json(1)) == json());
CHECK(j.value("boolean", false) == true);
CHECK(j.value("string", "bar") == "hello world");
CHECK(j.value("string", std::string("bar")) == "hello world");
CHECK(j.value("floating", 12.34) == Approx(42.23));
CHECK(j.value("floating", 12) == 42);
CHECK(j.value("object", json({{"foo", "bar"}})) == json(json::object()));
CHECK(j.value("array", json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value("integer", 2) == 1);
CHECK(j_const.value("integer", 1.0) == Approx(1));
CHECK(j_const.value("unsigned", 2) == 1u);
CHECK(j_const.value("unsigned", 1.0) == Approx(1u));
CHECK(j_const.value("boolean", false) == true);
CHECK(j_const.value("string", "bar") == "hello world");
CHECK(j_const.value("string", std::string("bar")) == "hello world");
CHECK(j_const.value("floating", 12.34) == Approx(42.23));
CHECK(j_const.value("floating", 12) == 42);
CHECK(j_const.value("object", json({{"foo", "bar"}})) == json(json::object()));
CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3}));
}
SECTION("access non-existing value")
{
CHECK(j.value("_", 2) == 2);
CHECK(j.value("_", 2u) == 2u);
CHECK(j.value("_", false) == false);
CHECK(j.value("_", "bar") == "bar");
CHECK(j.value("_", 12.34) == Approx(12.34));
CHECK(j.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j.value("_", json({10, 100})) == json({10, 100}));
CHECK(j_const.value("_", 2) == 2);
CHECK(j_const.value("_", 2u) == 2u);
CHECK(j_const.value("_", false) == false);
CHECK(j_const.value("_", "bar") == "bar");
CHECK(j_const.value("_", 12.34) == Approx(12.34));
CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value("_", json({10, 100})) == json({10, 100}));
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with null");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with boolean");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with string");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with string");
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with array");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with array");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number");
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number");
}
}
}
SECTION("given a JSON pointer")
{
SECTION("access existing value")
{
CHECK(j.value("/integer"_json_pointer, 2) == 1);
CHECK(j.value("/integer"_json_pointer, 1.0) == Approx(1));
CHECK(j.value("/unsigned"_json_pointer, 2) == 1u);
CHECK(j.value("/unsigned"_json_pointer, 1.0) == Approx(1u));
CHECK(j.value("/null"_json_pointer, json(1)) == json());
CHECK(j.value("/boolean"_json_pointer, false) == true);
CHECK(j.value("/string"_json_pointer, "bar") == "hello world");
CHECK(j.value("/string"_json_pointer, std::string("bar")) == "hello world");
CHECK(j.value("/floating"_json_pointer, 12.34) == Approx(42.23));
CHECK(j.value("/floating"_json_pointer, 12) == 42);
CHECK(j.value("/object"_json_pointer, json({{"foo", "bar"}})) == json(json::object()));
CHECK(j.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value("/integer"_json_pointer, 2) == 1);
CHECK(j_const.value("/integer"_json_pointer, 1.0) == Approx(1));
CHECK(j_const.value("/unsigned"_json_pointer, 2) == 1u);
CHECK(j_const.value("/unsigned"_json_pointer, 1.0) == Approx(1u));
CHECK(j_const.value("/boolean"_json_pointer, false) == true);
CHECK(j_const.value("/string"_json_pointer, "bar") == "hello world");
CHECK(j_const.value("/string"_json_pointer, std::string("bar")) == "hello world");
CHECK(j_const.value("/floating"_json_pointer, 12.34) == Approx(42.23));
CHECK(j_const.value("/floating"_json_pointer, 12) == 42);
CHECK(j_const.value("/object"_json_pointer, json({{"foo", "bar"}})) == json(json::object()));
CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
}
SECTION("access non-existing value")
{
CHECK(j.value("/not/existing"_json_pointer, 2) == 2);
CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u);
CHECK(j.value("/not/existing"_json_pointer, false) == false);
CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar");
CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2);
CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u);
CHECK(j_const.value("/not/existing"_json_pointer, false) == false);
CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar");
CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with null");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), "cannot use value() with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with boolean");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with string");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with string");
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with array");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), "cannot use value() with array");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with number");
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with number");
}
}
}
}
SECTION("front and back")
{
// "array" is the smallest key
CHECK(j.front() == json({1, 2, 3}));
CHECK(j_const.front() == json({1, 2, 3}));
// "unsigned" is the largest key
CHECK(j.back() == json(1u));
CHECK(j_const.back() == json(1u));
}
SECTION("access specified element")
{
SECTION("access within bounds")
{
CHECK(j["integer"] == json(1));
CHECK(j[json::object_t::key_type("integer")] == j["integer"]);
CHECK(j["unsigned"] == json(1u));
CHECK(j[json::object_t::key_type("unsigned")] == j["unsigned"]);
CHECK(j["boolean"] == json(true));
CHECK(j[json::object_t::key_type("boolean")] == j["boolean"]);
CHECK(j["null"] == json(nullptr));
CHECK(j[json::object_t::key_type("null")] == j["null"]);
CHECK(j["string"] == json("hello world"));
CHECK(j[json::object_t::key_type("string")] == j["string"]);
CHECK(j["floating"] == json(42.23));
CHECK(j[json::object_t::key_type("floating")] == j["floating"]);
CHECK(j["object"] == json(json::object()));
CHECK(j[json::object_t::key_type("object")] == j["object"]);
CHECK(j["array"] == json({1, 2, 3}));
CHECK(j[json::object_t::key_type("array")] == j["array"]);
CHECK(j_const["integer"] == json(1));
CHECK(j_const[json::object_t::key_type("integer")] == j["integer"]);
CHECK(j_const["boolean"] == json(true));
CHECK(j_const[json::object_t::key_type("boolean")] == j["boolean"]);
CHECK(j_const["null"] == json(nullptr));
CHECK(j_const[json::object_t::key_type("null")] == j["null"]);
CHECK(j_const["string"] == json("hello world"));
CHECK(j_const[json::object_t::key_type("string")] == j["string"]);
CHECK(j_const["floating"] == json(42.23));
CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]);
CHECK(j_const["object"] == json(json::object()));
CHECK(j_const[json::object_t::key_type("object")] == j["object"]);
CHECK(j_const["array"] == json({1, 2, 3}));
CHECK(j_const[json::object_t::key_type("array")] == j["array"]);
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
json j_nonobject2(json::value_t::null);
const json j_const_nonobject(j_nonobject);
CHECK_NOTHROW(j_nonobject["foo"]);
CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with null");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_const_nonobject(j_nonobject);
CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with boolean");
CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with boolean");
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with boolean");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_const_nonobject(j_nonobject);
CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with string");
CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with string");
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with string");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with string");
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_const_nonobject(j_nonobject);
CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with array");
CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "cannot use operator[] with array");
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with array");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with array");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_const_nonobject(j_nonobject);
CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with number");
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with number");
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_const_nonobject(j_nonobject);
CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with number");
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_const_nonobject(j_nonobject);
CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error);
CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error);
CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with number");
CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number");
CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")],
"cannot use operator[] with number");
}
}
}
SECTION("remove specified element")
{
SECTION("remove element by key")
{
CHECK(j.find("integer") != j.end());
CHECK(j.erase("integer") == 1);
CHECK(j.find("integer") == j.end());
CHECK(j.erase("integer") == 0);
CHECK(j.find("unsigned") != j.end());
CHECK(j.erase("unsigned") == 1);
CHECK(j.find("unsigned") == j.end());
CHECK(j.erase("unsigned") == 0);
CHECK(j.find("boolean") != j.end());
CHECK(j.erase("boolean") == 1);
CHECK(j.find("boolean") == j.end());
CHECK(j.erase("boolean") == 0);
CHECK(j.find("null") != j.end());
CHECK(j.erase("null") == 1);
CHECK(j.find("null") == j.end());
CHECK(j.erase("null") == 0);
CHECK(j.find("string") != j.end());
CHECK(j.erase("string") == 1);
CHECK(j.find("string") == j.end());
CHECK(j.erase("string") == 0);
CHECK(j.find("floating") != j.end());
CHECK(j.erase("floating") == 1);
CHECK(j.find("floating") == j.end());
CHECK(j.erase("floating") == 0);
CHECK(j.find("object") != j.end());
CHECK(j.erase("object") == 1);
CHECK(j.find("object") == j.end());
CHECK(j.erase("object") == 0);
CHECK(j.find("array") != j.end());
CHECK(j.erase("array") == 1);
CHECK(j.find("array") == j.end());
CHECK(j.erase("array") == 0);
}
SECTION("remove element by iterator")
{
SECTION("erase(begin())")
{
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::iterator it2 = jobject.erase(jobject.begin());
CHECK(jobject == json({{"b", 1}, {"c", 17u}}));
CHECK(*it2 == json(1));
}
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::const_iterator it2 = jobject.erase(jobject.cbegin());
CHECK(jobject == json({{"b", 1}, {"c", 17u}}));
CHECK(*it2 == json(1));
}
}
SECTION("erase(begin(), end())")
{
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::iterator it2 = jobject.erase(jobject.begin(), jobject.end());
CHECK(jobject == json::object());
CHECK(it2 == jobject.end());
}
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cend());
CHECK(jobject == json::object());
CHECK(it2 == jobject.cend());
}
}
SECTION("erase(begin(), begin())")
{
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::iterator it2 = jobject.erase(jobject.begin(), jobject.begin());
CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17u}}));
CHECK(*it2 == json("a"));
}
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cbegin());
CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17u}}));
CHECK(*it2 == json("a"));
}
}
SECTION("erase at offset")
{
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::iterator it = jobject.find("b");
json::iterator it2 = jobject.erase(it);
CHECK(jobject == json({{"a", "a"}, {"c", 17u}}));
CHECK(*it2 == json(17));
}
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}};
json::const_iterator it = jobject.find("b");
json::const_iterator it2 = jobject.erase(it);
CHECK(jobject == json({{"a", "a"}, {"c", 17u}}));
CHECK(*it2 == json(17));
}
}
SECTION("erase subrange")
{
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
json::iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e"));
CHECK(jobject == json({{"a", "a"}, {"e", true}}));
CHECK(*it2 == json(true));
}
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
json::const_iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e"));
CHECK(jobject == json({{"a", "a"}, {"e", true}}));
CHECK(*it2 == json(true));
}
}
SECTION("different objects")
{
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
CHECK_THROWS_AS(jobject.erase(jobject2.begin()), std::domain_error);
CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error);
CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error);
CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject2.end()), std::domain_error);
CHECK_THROWS_WITH(jobject.erase(jobject2.begin()), "iterator does not fit current value");
CHECK_THROWS_WITH(jobject.erase(jobject.begin(), jobject2.end()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject.end()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jobject.erase(jobject2.begin(), jobject2.end()),
"iterators do not fit current value");
}
{
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}};
json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}};
CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), std::domain_error);
CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error);
CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error);
CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), std::domain_error);
CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin()), "iterator does not fit current value");
CHECK_THROWS_WITH(jobject.erase(jobject.cbegin(), jobject2.cend()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject.cend()),
"iterators do not fit current value");
CHECK_THROWS_WITH(jobject.erase(jobject2.cbegin(), jobject2.cend()),
"iterators do not fit current value");
}
}
}
SECTION("remove element by key in non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with string");
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with array");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
CHECK_THROWS_AS(j_nonobject.erase("foo"), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.erase("foo"), "cannot use erase() with number");
}
}
}
SECTION("find an element in an object")
{
SECTION("existing element")
{
for (auto key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.find(key) != j.end());
CHECK(*j.find(key) == j.at(key));
CHECK(j_const.find(key) != j_const.end());
CHECK(*j_const.find(key) == j_const.at(key));
}
}
SECTION("nonexisting element")
{
CHECK(j.find("foo") == j.end());
CHECK(j_const.find("foo") == j_const.end());
}
SECTION("all types")
{
SECTION("null")
{
json j_nonarray(json::value_t::null);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("string")
{
json j_nonarray(json::value_t::string);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("object")
{
json j_nonarray(json::value_t::object);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("array")
{
json j_nonarray(json::value_t::array);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("boolean")
{
json j_nonarray(json::value_t::boolean);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("number (integer)")
{
json j_nonarray(json::value_t::number_integer);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("number (unsigned)")
{
json j_nonarray(json::value_t::number_unsigned);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
SECTION("number (floating-point)")
{
json j_nonarray(json::value_t::number_float);
const json j_nonarray_const(j_nonarray);
CHECK(j_nonarray.find("foo") == j_nonarray.end());
CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end());
}
}
}
SECTION("count keys in an object")
{
SECTION("existing element")
{
for (auto key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.count(key) == 1);
CHECK(j_const.count(key) == 1);
}
}
SECTION("nonexisting element")
{
CHECK(j.count("foo") == 0);
CHECK(j_const.count("foo") == 0);
}
SECTION("all types")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("object")
{
json j_nonobject(json::value_t::object);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.count("foo") == 0);
CHECK(j_nonobject_const.count("foo") == 0);
}
}
}
}
}

View File

@ -0,0 +1,373 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("object inspection")
{
SECTION("convenience type checker")
{
SECTION("object")
{
json j {{"foo", 1}, {"bar", false}};
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(not j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(not j.is_primitive());
CHECK(j.is_structured());
}
SECTION("array")
{
json j {"foo", 1, 1u, 42.23, false};
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(not j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(not j.is_primitive());
CHECK(j.is_structured());
}
SECTION("null")
{
json j(nullptr);
CHECK(j.is_null());
CHECK(not j.is_boolean());
CHECK(not j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(j.is_primitive());
CHECK(not j.is_structured());
}
SECTION("boolean")
{
json j(true);
CHECK(not j.is_null());
CHECK(j.is_boolean());
CHECK(not j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(j.is_primitive());
CHECK(not j.is_structured());
}
SECTION("string")
{
json j("Hello world");
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(not j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(j.is_string());
CHECK(not j.is_discarded());
CHECK(j.is_primitive());
CHECK(not j.is_structured());
}
SECTION("number (integer)")
{
json j(42);
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(j.is_number());
CHECK(j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(j.is_primitive());
CHECK(not j.is_structured());
}
SECTION("number (unsigned)")
{
json j(42u);
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(j.is_number());
CHECK(j.is_number_integer());
CHECK(j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(j.is_primitive());
CHECK(not j.is_structured());
}
SECTION("number (floating-point)")
{
json j(42.23);
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(not j.is_discarded());
CHECK(j.is_primitive());
CHECK(not j.is_structured());
}
SECTION("discarded")
{
json j(json::value_t::discarded);
CHECK(not j.is_null());
CHECK(not j.is_boolean());
CHECK(not j.is_number());
CHECK(not j.is_number_integer());
CHECK(not j.is_number_unsigned());
CHECK(not j.is_number_float());
CHECK(not j.is_object());
CHECK(not j.is_array());
CHECK(not j.is_string());
CHECK(j.is_discarded());
CHECK(not j.is_primitive());
CHECK(not j.is_structured());
}
}
SECTION("serialization")
{
json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
SECTION("no indent / indent=-1")
{
CHECK(j.dump() ==
"{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
CHECK(j.dump() == j.dump(-1));
}
SECTION("indent=0")
{
CHECK(j.dump(0) ==
"{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
}
SECTION("indent=4")
{
CHECK(j.dump(4) ==
"{\n \"array\": [\n 1,\n 2,\n 3,\n 4\n ],\n \"boolean\": false,\n \"null\": null,\n \"number\": 42,\n \"object\": {},\n \"string\": \"Hello world\"\n}");
}
SECTION("dump and floating-point numbers")
{
auto s = json(42.23).dump();
CHECK(s.find("42.23") != std::string::npos);
}
SECTION("dump and small floating-point numbers")
{
auto s = json(1.23456e-78).dump();
CHECK(s.find("1.23456e-78") != std::string::npos);
}
SECTION("dump and non-ASCII characters")
{
CHECK(json("ä").dump() == "\"ä\"");
CHECK(json("Ö").dump() == "\"Ö\"");
CHECK(json("❤️").dump() == "\"❤️\"");
}
SECTION("serialization of discarded element")
{
json j_discarded(json::value_t::discarded);
CHECK(j_discarded.dump() == "<discarded>");
}
SECTION("check that precision is reset after serialization")
{
// create stringstream and set precision
std::stringstream ss;
ss.precision(3);
ss << 3.141592653589793 << std::fixed;
CHECK(ss.str() == "3.14");
// reset stringstream
ss.str(std::string());
// use stringstream for JSON serialization
json j_number = 3.141592653589793;
ss << j_number;
// check that precision has been overridden during serialization
CHECK(ss.str() == "3.141592653589793");
// check that precision has been restored
CHECK(ss.precision() == 3);
}
}
SECTION("return the type of the object (explicit)")
{
SECTION("null")
{
json j = nullptr;
CHECK(j.type() == json::value_t::null);
}
SECTION("object")
{
json j = {{"foo", "bar"}};
CHECK(j.type() == json::value_t::object);
}
SECTION("array")
{
json j = {1, 2, 3, 4};
CHECK(j.type() == json::value_t::array);
}
SECTION("boolean")
{
json j = true;
CHECK(j.type() == json::value_t::boolean);
}
SECTION("string")
{
json j = "Hello world";
CHECK(j.type() == json::value_t::string);
}
SECTION("number (integer)")
{
json j = 23;
CHECK(j.type() == json::value_t::number_integer);
}
SECTION("number (unsigned)")
{
json j = 23u;
CHECK(j.type() == json::value_t::number_unsigned);
}
SECTION("number (floating-point)")
{
json j = 42.23;
CHECK(j.type() == json::value_t::number_float);
}
}
SECTION("return the type of the object (implicit)")
{
SECTION("null")
{
json j = nullptr;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("object")
{
json j = {{"foo", "bar"}};
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("array")
{
json j = {1, 2, 3, 4};
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("boolean")
{
json j = true;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("string")
{
json j = "Hello world";
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("number (integer)")
{
json j = 23;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("number (unsigned)")
{
json j = 23u;
json::value_t t = j;
CHECK(t == j.type());
}
SECTION("number (floating-point)")
{
json j = 42.23;
json::value_t t = j;
CHECK(t == j.type());
}
}
}

View File

@ -0,0 +1,729 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("iterator_wrapper")
{
SECTION("object")
{
SECTION("value")
{
json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("reference")
{
json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
// change the value
i.value() = json(11);
CHECK(i.value() == json(11));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
// change the value
i.value() = json(22);
CHECK(i.value() == json(22));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
// check if values where changed
CHECK(j == json({{"A", 11}, {"B", 22}}));
}
SECTION("const value")
{
json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const reference")
{
json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
}
SECTION("const object")
{
SECTION("value")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("reference")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const value")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const reference")
{
const json j = {{"A", 1}, {"B", 2}};
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "A");
CHECK(i.value() == json(1));
break;
}
case 2:
{
CHECK(i.key() == "B");
CHECK(i.value() == json(2));
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
}
SECTION("array")
{
SECTION("value")
{
json j = {"A", "B"};
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("reference")
{
json j = {"A", "B"};
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
// change the value
i.value() = "AA";
CHECK(i.value() == "AA");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
// change the value
i.value() = "BB";
CHECK(i.value() == "BB");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
// check if values where changed
CHECK(j == json({"AA", "BB"}));
}
SECTION("const value")
{
json j = {"A", "B"};
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const reference")
{
json j = {"A", "B"};
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
}
SECTION("const array")
{
SECTION("value")
{
const json j = {"A", "B"};
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("reference")
{
const json j = {"A", "B"};
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const value")
{
const json j = {"A", "B"};
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
SECTION("const reference")
{
const json j = {"A", "B"};
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
switch (counter++)
{
case 1:
{
CHECK(i.key() == "0");
CHECK(i.value() == "A");
break;
}
case 2:
{
CHECK(i.key() == "1");
CHECK(i.value() == "B");
break;
}
default:
{
break;
}
}
}
CHECK(counter == 3);
}
}
SECTION("primitive")
{
SECTION("value")
{
json j = 1;
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("reference")
{
json j = 1;
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
// change value
i.value() = json(2);
}
CHECK(counter == 2);
// check if value has changed
CHECK(j == json(2));
}
SECTION("const value")
{
json j = 1;
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("const reference")
{
json j = 1;
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
}
SECTION("const primitive")
{
SECTION("value")
{
const json j = 1;
int counter = 1;
for (auto i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("reference")
{
const json j = 1;
int counter = 1;
for (auto& i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("const value")
{
const json j = 1;
int counter = 1;
for (const auto i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
SECTION("const reference")
{
const json j = 1;
int counter = 1;
for (const auto& i : json::iterator_wrapper(j))
{
++counter;
CHECK(i.key() == "");
CHECK(i.value() == json(1));
}
CHECK(counter == 2);
}
}
}

1514
test/src/unit-iterators1.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,873 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("iterators 2")
{
SECTION("iterator comparisons")
{
json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
for (json& j : j_values)
{
auto it1 = j.begin();
auto it2 = j.begin();
auto it3 = j.begin();
++it2;
++it3;
++it3;
auto it1_c = j.cbegin();
auto it2_c = j.cbegin();
auto it3_c = j.cbegin();
++it2_c;
++it3_c;
++it3_c;
// comparison: equal
{
CHECK(it1 == it1);
CHECK(not (it1 == it2));
CHECK(not (it1 == it3));
CHECK(not (it2 == it3));
CHECK(it1_c == it1_c);
CHECK(not (it1_c == it2_c));
CHECK(not (it1_c == it3_c));
CHECK(not (it2_c == it3_c));
}
// comparison: not equal
{
// check definition
CHECK( (it1 != it1) == not(it1 == it1) );
CHECK( (it1 != it2) == not(it1 == it2) );
CHECK( (it1 != it3) == not(it1 == it3) );
CHECK( (it2 != it3) == not(it2 == it3) );
CHECK( (it1_c != it1_c) == not(it1_c == it1_c) );
CHECK( (it1_c != it2_c) == not(it1_c == it2_c) );
CHECK( (it1_c != it3_c) == not(it1_c == it3_c) );
CHECK( (it2_c != it3_c) == not(it2_c == it3_c) );
}
// comparison: smaller
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 < it1, std::domain_error);
CHECK_THROWS_AS(it1 < it2, std::domain_error);
CHECK_THROWS_AS(it2 < it3, std::domain_error);
CHECK_THROWS_AS(it1 < it3, std::domain_error);
CHECK_THROWS_AS(it1_c < it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c < it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c < it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c < it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators");
}
else
{
CHECK(not (it1 < it1));
CHECK(it1 < it2);
CHECK(it1 < it3);
CHECK(it2 < it3);
CHECK(not (it1_c < it1_c));
CHECK(it1_c < it2_c);
CHECK(it1_c < it3_c);
CHECK(it2_c < it3_c);
}
}
// comparison: less than or equal
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 <= it1, std::domain_error);
CHECK_THROWS_AS(it1 <= it2, std::domain_error);
CHECK_THROWS_AS(it2 <= it3, std::domain_error);
CHECK_THROWS_AS(it1 <= it3, std::domain_error);
CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators");
}
else
{
// check definition
CHECK( (it1 <= it1) == not(it1 < it1) );
CHECK( (it1 <= it2) == not(it2 < it1) );
CHECK( (it1 <= it3) == not(it3 < it1) );
CHECK( (it2 <= it3) == not(it3 < it2) );
CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) );
CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) );
CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) );
CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) );
}
}
// comparison: greater than
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 > it1, std::domain_error);
CHECK_THROWS_AS(it1 > it2, std::domain_error);
CHECK_THROWS_AS(it2 > it3, std::domain_error);
CHECK_THROWS_AS(it1 > it3, std::domain_error);
CHECK_THROWS_AS(it1_c > it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c > it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c > it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c > it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators");
}
else
{
// check definition
CHECK( (it1 > it1) == (it1 < it1) );
CHECK( (it1 > it2) == (it2 < it1) );
CHECK( (it1 > it3) == (it3 < it1) );
CHECK( (it2 > it3) == (it3 < it2) );
CHECK( (it1_c > it1_c) == (it1_c < it1_c) );
CHECK( (it1_c > it2_c) == (it2_c < it1_c) );
CHECK( (it1_c > it3_c) == (it3_c < it1_c) );
CHECK( (it2_c > it3_c) == (it3_c < it2_c) );
}
}
// comparison: greater than or equal
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 >= it1, std::domain_error);
CHECK_THROWS_AS(it1 >= it2, std::domain_error);
CHECK_THROWS_AS(it2 >= it3, std::domain_error);
CHECK_THROWS_AS(it1 >= it3, std::domain_error);
CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators");
}
else
{
// check definition
CHECK( (it1 >= it1) == not(it1 < it1) );
CHECK( (it1 >= it2) == not(it1 < it2) );
CHECK( (it1 >= it3) == not(it1 < it3) );
CHECK( (it2 >= it3) == not(it2 < it3) );
CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) );
CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) );
CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) );
CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) );
}
}
}
// check exceptions if different objects are compared
for (auto j : j_values)
{
for (auto k : j_values)
{
if (j != k)
{
CHECK_THROWS_AS(j.begin() == k.begin(), std::domain_error);
CHECK_THROWS_AS(j.cbegin() == k.cbegin(), std::domain_error);
CHECK_THROWS_WITH(j.begin() == k.begin(), "cannot compare iterators of different containers");
CHECK_THROWS_WITH(j.cbegin() == k.cbegin(), "cannot compare iterators of different containers");
CHECK_THROWS_AS(j.begin() < k.begin(), std::domain_error);
CHECK_THROWS_AS(j.cbegin() < k.cbegin(), std::domain_error);
CHECK_THROWS_WITH(j.begin() < k.begin(), "cannot compare iterators of different containers");
CHECK_THROWS_WITH(j.cbegin() < k.cbegin(), "cannot compare iterators of different containers");
}
}
}
}
SECTION("iterator arithmetic")
{
json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_array = {1, 2, 3, 4, 5, 6};
json j_null = nullptr;
json j_value = 42;
SECTION("addition and subtraction")
{
SECTION("object")
{
{
auto it = j_object.begin();
CHECK_THROWS_AS(it += 1, std::domain_error);
CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.cbegin();
CHECK_THROWS_AS(it += 1, std::domain_error);
CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.begin();
CHECK_THROWS_AS(it + 1, std::domain_error);
CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.cbegin();
CHECK_THROWS_AS(it + 1, std::domain_error);
CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.begin();
CHECK_THROWS_AS(it -= 1, std::domain_error);
CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.cbegin();
CHECK_THROWS_AS(it -= 1, std::domain_error);
CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.begin();
CHECK_THROWS_AS(it - 1, std::domain_error);
CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.cbegin();
CHECK_THROWS_AS(it - 1, std::domain_error);
CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.begin();
CHECK_THROWS_AS(it - it, std::domain_error);
CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators");
}
{
auto it = j_object.cbegin();
CHECK_THROWS_AS(it - it, std::domain_error);
CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators");
}
}
SECTION("array")
{
{
auto it = j_array.begin();
it += 3;
CHECK((j_array.begin() + 3) == it);
CHECK((it - 3) == j_array.begin());
CHECK((it - j_array.begin()) == 3);
CHECK(*it == json(4));
it -= 2;
CHECK(*it == json(2));
}
{
auto it = j_array.cbegin();
it += 3;
CHECK((j_array.cbegin() + 3) == it);
CHECK((it - 3) == j_array.cbegin());
CHECK((it - j_array.cbegin()) == 3);
CHECK(*it == json(4));
it -= 2;
CHECK(*it == json(2));
}
}
SECTION("null")
{
{
auto it = j_null.begin();
it += 3;
CHECK((j_null.begin() + 3) == it);
CHECK((it - 3) == j_null.begin());
CHECK((it - j_null.begin()) == 3);
CHECK(it != j_null.end());
it -= 3;
CHECK(it == j_null.end());
}
{
auto it = j_null.cbegin();
it += 3;
CHECK((j_null.cbegin() + 3) == it);
CHECK((it - 3) == j_null.cbegin());
CHECK((it - j_null.cbegin()) == 3);
CHECK(it != j_null.cend());
it -= 3;
CHECK(it == j_null.cend());
}
}
SECTION("value")
{
{
auto it = j_value.begin();
it += 3;
CHECK((j_value.begin() + 3) == it);
CHECK((it - 3) == j_value.begin());
CHECK((it - j_value.begin()) == 3);
CHECK(it != j_value.end());
it -= 3;
CHECK(*it == json(42));
}
{
auto it = j_value.cbegin();
it += 3;
CHECK((j_value.cbegin() + 3) == it);
CHECK((it - 3) == j_value.cbegin());
CHECK((it - j_value.cbegin()) == 3);
CHECK(it != j_value.cend());
it -= 3;
CHECK(*it == json(42));
}
}
}
SECTION("subscript operator")
{
SECTION("object")
{
{
auto it = j_object.begin();
CHECK_THROWS_AS(it[0], std::domain_error);
CHECK_THROWS_AS(it[1], std::domain_error);
CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators");
CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators");
}
{
auto it = j_object.cbegin();
CHECK_THROWS_AS(it[0], std::domain_error);
CHECK_THROWS_AS(it[1], std::domain_error);
CHECK_THROWS_WITH(it[0], "cannot use operator[] for object iterators");
CHECK_THROWS_WITH(it[1], "cannot use operator[] for object iterators");
}
}
SECTION("array")
{
{
auto it = j_array.begin();
CHECK(it[0] == json(1));
CHECK(it[1] == json(2));
CHECK(it[2] == json(3));
CHECK(it[3] == json(4));
CHECK(it[4] == json(5));
CHECK(it[5] == json(6));
}
{
auto it = j_array.cbegin();
CHECK(it[0] == json(1));
CHECK(it[1] == json(2));
CHECK(it[2] == json(3));
CHECK(it[3] == json(4));
CHECK(it[4] == json(5));
CHECK(it[5] == json(6));
}
}
SECTION("null")
{
{
auto it = j_null.begin();
CHECK_THROWS_AS(it[0], std::out_of_range);
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[0], "cannot get value");
CHECK_THROWS_WITH(it[1], "cannot get value");
}
{
auto it = j_null.cbegin();
CHECK_THROWS_AS(it[0], std::out_of_range);
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[0], "cannot get value");
CHECK_THROWS_WITH(it[1], "cannot get value");
}
}
SECTION("value")
{
{
auto it = j_value.begin();
CHECK(it[0] == json(42));
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[1], "cannot get value");
}
{
auto it = j_value.cbegin();
CHECK(it[0] == json(42));
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[1], "cannot get value");
}
}
}
}
SECTION("reverse iterator comparisons")
{
json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
for (json& j : j_values)
{
auto it1 = j.rbegin();
auto it2 = j.rbegin();
auto it3 = j.rbegin();
++it2;
++it3;
++it3;
auto it1_c = j.crbegin();
auto it2_c = j.crbegin();
auto it3_c = j.crbegin();
++it2_c;
++it3_c;
++it3_c;
// comparison: equal
{
CHECK(it1 == it1);
CHECK(not (it1 == it2));
CHECK(not (it1 == it3));
CHECK(not (it2 == it3));
CHECK(it1_c == it1_c);
CHECK(not (it1_c == it2_c));
CHECK(not (it1_c == it3_c));
CHECK(not (it2_c == it3_c));
}
// comparison: not equal
{
// check definition
CHECK( (it1 != it1) == not(it1 == it1) );
CHECK( (it1 != it2) == not(it1 == it2) );
CHECK( (it1 != it3) == not(it1 == it3) );
CHECK( (it2 != it3) == not(it2 == it3) );
CHECK( (it1_c != it1_c) == not(it1_c == it1_c) );
CHECK( (it1_c != it2_c) == not(it1_c == it2_c) );
CHECK( (it1_c != it3_c) == not(it1_c == it3_c) );
CHECK( (it2_c != it3_c) == not(it2_c == it3_c) );
}
// comparison: smaller
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 < it1, std::domain_error);
CHECK_THROWS_AS(it1 < it2, std::domain_error);
CHECK_THROWS_AS(it2 < it3, std::domain_error);
CHECK_THROWS_AS(it1 < it3, std::domain_error);
CHECK_THROWS_AS(it1_c < it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c < it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c < it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c < it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 < it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 < it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 < it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 < it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c < it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c < it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c < it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c < it3_c, "cannot compare order of object iterators");
}
else
{
CHECK(not (it1 < it1));
CHECK(it1 < it2);
CHECK(it1 < it3);
CHECK(it2 < it3);
CHECK(not (it1_c < it1_c));
CHECK(it1_c < it2_c);
CHECK(it1_c < it3_c);
CHECK(it2_c < it3_c);
}
}
// comparison: less than or equal
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 <= it1, std::domain_error);
CHECK_THROWS_AS(it1 <= it2, std::domain_error);
CHECK_THROWS_AS(it2 <= it3, std::domain_error);
CHECK_THROWS_AS(it1 <= it3, std::domain_error);
CHECK_THROWS_AS(it1_c <= it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c <= it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c <= it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c <= it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 <= it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 <= it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 <= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 <= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c <= it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c <= it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c <= it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c <= it3_c, "cannot compare order of object iterators");
}
else
{
// check definition
CHECK( (it1 <= it1) == not(it1 < it1) );
CHECK( (it1 <= it2) == not(it2 < it1) );
CHECK( (it1 <= it3) == not(it3 < it1) );
CHECK( (it2 <= it3) == not(it3 < it2) );
CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) );
CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) );
CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) );
CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) );
}
}
// comparison: greater than
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 > it1, std::domain_error);
CHECK_THROWS_AS(it1 > it2, std::domain_error);
CHECK_THROWS_AS(it2 > it3, std::domain_error);
CHECK_THROWS_AS(it1 > it3, std::domain_error);
CHECK_THROWS_AS(it1_c > it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c > it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c > it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c > it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 > it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 > it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 > it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 > it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c > it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c > it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c > it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c > it3_c, "cannot compare order of object iterators");
}
else
{
// check definition
CHECK( (it1 > it1) == (it1 < it1) );
CHECK( (it1 > it2) == (it2 < it1) );
CHECK( (it1 > it3) == (it3 < it1) );
CHECK( (it2 > it3) == (it3 < it2) );
CHECK( (it1_c > it1_c) == (it1_c < it1_c) );
CHECK( (it1_c > it2_c) == (it2_c < it1_c) );
CHECK( (it1_c > it3_c) == (it3_c < it1_c) );
CHECK( (it2_c > it3_c) == (it3_c < it2_c) );
}
}
// comparison: greater than or equal
{
if (j.type() == json::value_t::object)
{
CHECK_THROWS_AS(it1 >= it1, std::domain_error);
CHECK_THROWS_AS(it1 >= it2, std::domain_error);
CHECK_THROWS_AS(it2 >= it3, std::domain_error);
CHECK_THROWS_AS(it1 >= it3, std::domain_error);
CHECK_THROWS_AS(it1_c >= it1_c, std::domain_error);
CHECK_THROWS_AS(it1_c >= it2_c, std::domain_error);
CHECK_THROWS_AS(it2_c >= it3_c, std::domain_error);
CHECK_THROWS_AS(it1_c >= it3_c, std::domain_error);
CHECK_THROWS_WITH(it1 >= it1, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 >= it2, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2 >= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1 >= it3, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c >= it1_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c >= it2_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it2_c >= it3_c, "cannot compare order of object iterators");
CHECK_THROWS_WITH(it1_c >= it3_c, "cannot compare order of object iterators");
}
else
{
// check definition
CHECK( (it1 >= it1) == not(it1 < it1) );
CHECK( (it1 >= it2) == not(it1 < it2) );
CHECK( (it1 >= it3) == not(it1 < it3) );
CHECK( (it2 >= it3) == not(it2 < it3) );
CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) );
CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) );
CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) );
CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) );
}
}
}
// check exceptions if different objects are compared
for (auto j : j_values)
{
for (auto k : j_values)
{
if (j != k)
{
CHECK_THROWS_AS(j.rbegin() == k.rbegin(), std::domain_error);
CHECK_THROWS_AS(j.crbegin() == k.crbegin(), std::domain_error);
CHECK_THROWS_WITH(j.rbegin() == k.rbegin(), "cannot compare iterators of different containers");
CHECK_THROWS_WITH(j.crbegin() == k.crbegin(), "cannot compare iterators of different containers");
CHECK_THROWS_AS(j.rbegin() < k.rbegin(), std::domain_error);
CHECK_THROWS_AS(j.crbegin() < k.crbegin(), std::domain_error);
CHECK_THROWS_WITH(j.rbegin() < k.rbegin(), "cannot compare iterators of different containers");
CHECK_THROWS_WITH(j.crbegin() < k.crbegin(), "cannot compare iterators of different containers");
}
}
}
}
SECTION("reverse iterator arithmetic")
{
json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
json j_array = {1, 2, 3, 4, 5, 6};
json j_null = nullptr;
json j_value = 42;
SECTION("addition and subtraction")
{
SECTION("object")
{
{
auto it = j_object.rbegin();
CHECK_THROWS_AS(it += 1, std::domain_error);
CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.crbegin();
CHECK_THROWS_AS(it += 1, std::domain_error);
CHECK_THROWS_WITH(it += 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.rbegin();
CHECK_THROWS_AS(it + 1, std::domain_error);
CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.crbegin();
CHECK_THROWS_AS(it + 1, std::domain_error);
CHECK_THROWS_WITH(it + 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.rbegin();
CHECK_THROWS_AS(it -= 1, std::domain_error);
CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.crbegin();
CHECK_THROWS_AS(it -= 1, std::domain_error);
CHECK_THROWS_WITH(it -= 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.rbegin();
CHECK_THROWS_AS(it - 1, std::domain_error);
CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.crbegin();
CHECK_THROWS_AS(it - 1, std::domain_error);
CHECK_THROWS_WITH(it - 1, "cannot use offsets with object iterators");
}
{
auto it = j_object.rbegin();
CHECK_THROWS_AS(it - it, std::domain_error);
CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators");
}
{
auto it = j_object.crbegin();
CHECK_THROWS_AS(it - it, std::domain_error);
CHECK_THROWS_WITH(it - it, "cannot use offsets with object iterators");
}
}
SECTION("array")
{
{
auto it = j_array.rbegin();
it += 3;
CHECK((j_array.rbegin() + 3) == it);
CHECK((it - 3) == j_array.rbegin());
CHECK((j_array.rbegin() - it) == 3);
CHECK(*it == json(3));
it -= 2;
CHECK(*it == json(5));
}
{
auto it = j_array.crbegin();
it += 3;
CHECK((j_array.crbegin() + 3) == it);
CHECK((it - 3) == j_array.crbegin());
CHECK((j_array.crbegin() - it) == 3);
CHECK(*it == json(3));
it -= 2;
CHECK(*it == json(5));
}
}
SECTION("null")
{
{
auto it = j_null.rbegin();
it += 3;
CHECK((j_null.rbegin() + 3) == it);
CHECK((it - 3) == j_null.rbegin());
CHECK((j_null.rbegin() - it) == 3);
CHECK(it != j_null.rend());
it -= 3;
CHECK(it == j_null.rend());
}
{
auto it = j_null.crbegin();
it += 3;
CHECK((j_null.crbegin() + 3) == it);
CHECK((it - 3) == j_null.crbegin());
CHECK((j_null.crbegin() - it) == 3);
CHECK(it != j_null.crend());
it -= 3;
CHECK(it == j_null.crend());
}
}
SECTION("value")
{
{
auto it = j_value.rbegin();
it += 3;
CHECK((j_value.rbegin() + 3) == it);
CHECK((it - 3) == j_value.rbegin());
CHECK((j_value.rbegin() - it) == 3);
CHECK(it != j_value.rend());
it -= 3;
CHECK(*it == json(42));
}
{
auto it = j_value.crbegin();
it += 3;
CHECK((j_value.crbegin() + 3) == it);
CHECK((it - 3) == j_value.crbegin());
CHECK((j_value.crbegin() - it) == 3);
CHECK(it != j_value.crend());
it -= 3;
CHECK(*it == json(42));
}
}
}
SECTION("subscript operator")
{
SECTION("object")
{
{
auto it = j_object.rbegin();
CHECK_THROWS_AS(it[0], std::domain_error);
CHECK_THROWS_AS(it[1], std::domain_error);
CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators");
CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators");
}
{
auto it = j_object.crbegin();
CHECK_THROWS_AS(it[0], std::domain_error);
CHECK_THROWS_AS(it[1], std::domain_error);
CHECK_THROWS_WITH(it[0], "cannot use offsets with object iterators");
CHECK_THROWS_WITH(it[1], "cannot use offsets with object iterators");
}
}
SECTION("array")
{
{
auto it = j_array.rbegin();
CHECK(it[0] == json(6));
CHECK(it[1] == json(5));
CHECK(it[2] == json(4));
CHECK(it[3] == json(3));
CHECK(it[4] == json(2));
CHECK(it[5] == json(1));
}
{
auto it = j_array.crbegin();
CHECK(it[0] == json(6));
CHECK(it[1] == json(5));
CHECK(it[2] == json(4));
CHECK(it[3] == json(3));
CHECK(it[4] == json(2));
CHECK(it[5] == json(1));
}
}
SECTION("null")
{
{
auto it = j_null.rbegin();
CHECK_THROWS_AS(it[0], std::out_of_range);
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[0], "cannot get value");
CHECK_THROWS_WITH(it[1], "cannot get value");
}
{
auto it = j_null.crbegin();
CHECK_THROWS_AS(it[0], std::out_of_range);
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[0], "cannot get value");
CHECK_THROWS_WITH(it[1], "cannot get value");
}
}
SECTION("value")
{
{
auto it = j_value.rbegin();
CHECK(it[0] == json(42));
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[1], "cannot get value");
}
{
auto it = j_value.crbegin();
CHECK(it[0] == json(42));
CHECK_THROWS_AS(it[1], std::out_of_range);
CHECK_THROWS_WITH(it[1], "cannot get value");
}
}
}
}
}

1217
test/src/unit-json_patch.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,388 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
TEST_CASE("JSON pointers")
{
SECTION("errors")
{
CHECK_THROWS_AS(json::json_pointer("foo"), std::domain_error);
CHECK_THROWS_WITH(json::json_pointer("foo"), "JSON pointer must be empty or begin with '/'");
CHECK_THROWS_AS(json::json_pointer("/~~"), std::domain_error);
CHECK_THROWS_WITH(json::json_pointer("/~~"), "escape error: '~' must be followed with '0' or '1'");
CHECK_THROWS_AS(json::json_pointer("/~"), std::domain_error);
CHECK_THROWS_WITH(json::json_pointer("/~"), "escape error: '~' must be followed with '0' or '1'");
json::json_pointer p;
CHECK_THROWS_AS(p.top(), std::domain_error);
CHECK_THROWS_WITH(p.top(), "JSON pointer has no parent");
CHECK_THROWS_AS(p.pop_back(), std::domain_error);
CHECK_THROWS_WITH(p.pop_back(), "JSON pointer has no parent");
}
SECTION("examples from RFC 6901")
{
SECTION("nonconst access")
{
json j = R"(
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
)"_json;
// the whole document
CHECK(j[json::json_pointer()] == j);
CHECK(j[json::json_pointer("")] == j);
// array access
CHECK(j[json::json_pointer("/foo")] == j["foo"]);
CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]);
CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]);
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
// checked array access
CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]);
CHECK(j.at(json::json_pointer("/foo/1")) == j["foo"][1]);
// empty string access
CHECK(j[json::json_pointer("/")] == j[""]);
// other cases
CHECK(j[json::json_pointer("/ ")] == j[" "]);
CHECK(j[json::json_pointer("/c%d")] == j["c%d"]);
CHECK(j[json::json_pointer("/e^f")] == j["e^f"]);
CHECK(j[json::json_pointer("/g|h")] == j["g|h"]);
CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]);
CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]);
// checked access
CHECK(j.at(json::json_pointer("/ ")) == j[" "]);
CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]);
CHECK(j.at(json::json_pointer("/e^f")) == j["e^f"]);
CHECK(j.at(json::json_pointer("/g|h")) == j["g|h"]);
CHECK(j.at(json::json_pointer("/i\\j")) == j["i\\j"]);
CHECK(j.at(json::json_pointer("/k\"l")) == j["k\"l"]);
// escaped access
CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]);
CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
// unescaped access
CHECK_THROWS_AS(j[json::json_pointer("/a/b")], std::out_of_range);
CHECK_THROWS_WITH(j[json::json_pointer("/a/b")], "unresolved reference token 'b'");
// "/a/b" works for JSON {"a": {"b": 42}}
CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42));
// unresolved access
json j_primitive = 1;
CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], std::out_of_range);
CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "unresolved reference token 'foo'");
CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "unresolved reference token 'foo'");
}
SECTION("const access")
{
const json j = R"(
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
)"_json;
// the whole document
CHECK(j[json::json_pointer()] == j);
CHECK(j[json::json_pointer("")] == j);
// array access
CHECK(j[json::json_pointer("/foo")] == j["foo"]);
CHECK(j[json::json_pointer("/foo/0")] == j["foo"][0]);
CHECK(j[json::json_pointer("/foo/1")] == j["foo"][1]);
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
// checked array access
CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]);
CHECK(j.at(json::json_pointer("/foo/1")) == j["foo"][1]);
// empty string access
CHECK(j[json::json_pointer("/")] == j[""]);
// other cases
CHECK(j[json::json_pointer("/ ")] == j[" "]);
CHECK(j[json::json_pointer("/c%d")] == j["c%d"]);
CHECK(j[json::json_pointer("/e^f")] == j["e^f"]);
CHECK(j[json::json_pointer("/g|h")] == j["g|h"]);
CHECK(j[json::json_pointer("/i\\j")] == j["i\\j"]);
CHECK(j[json::json_pointer("/k\"l")] == j["k\"l"]);
// checked access
CHECK(j.at(json::json_pointer("/ ")) == j[" "]);
CHECK(j.at(json::json_pointer("/c%d")) == j["c%d"]);
CHECK(j.at(json::json_pointer("/e^f")) == j["e^f"]);
CHECK(j.at(json::json_pointer("/g|h")) == j["g|h"]);
CHECK(j.at(json::json_pointer("/i\\j")) == j["i\\j"]);
CHECK(j.at(json::json_pointer("/k\"l")) == j["k\"l"]);
// escaped access
CHECK(j[json::json_pointer("/a~1b")] == j["a/b"]);
CHECK(j[json::json_pointer("/m~0n")] == j["m~n"]);
// unescaped access
CHECK_THROWS_AS(j.at(json::json_pointer("/a/b")), std::out_of_range);
CHECK_THROWS_WITH(j.at(json::json_pointer("/a/b")), "key 'a' not found");
// unresolved access
const json j_primitive = 1;
CHECK_THROWS_AS(j_primitive["/foo"_json_pointer], std::out_of_range);
CHECK_THROWS_WITH(j_primitive["/foo"_json_pointer], "unresolved reference token 'foo'");
CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), "unresolved reference token 'foo'");
}
SECTION("user-defined string literal")
{
json j = R"(
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
)"_json;
// the whole document
CHECK(j[""_json_pointer] == j);
// array access
CHECK(j["/foo"_json_pointer] == j["foo"]);
CHECK(j["/foo/0"_json_pointer] == j["foo"][0]);
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
}
}
SECTION("array access")
{
SECTION("nonconst access")
{
json j = {1, 2, 3};
const json j_const = j;
// check reading access
CHECK(j["/0"_json_pointer] == j[0]);
CHECK(j["/1"_json_pointer] == j[1]);
CHECK(j["/2"_json_pointer] == j[2]);
// assign to existing index
j["/1"_json_pointer] = 13;
CHECK(j[1] == json(13));
// assign to nonexisting index
j["/3"_json_pointer] = 33;
CHECK(j[3] == json(33));
// assign to nonexisting index (with gap)
j["/5"_json_pointer] = 55;
CHECK(j == json({1, 13, 3, 33, nullptr, 55}));
// error with leading 0
CHECK_THROWS_AS(j["/01"_json_pointer], std::domain_error);
CHECK_THROWS_WITH(j["/01"_json_pointer], "array index must not begin with '0'");
CHECK_THROWS_AS(j_const["/01"_json_pointer], std::domain_error);
CHECK_THROWS_WITH(j_const["/01"_json_pointer], "array index must not begin with '0'");
CHECK_THROWS_AS(j.at("/01"_json_pointer), std::domain_error);
CHECK_THROWS_WITH(j.at("/01"_json_pointer), "array index must not begin with '0'");
CHECK_THROWS_AS(j_const.at("/01"_json_pointer), std::domain_error);
CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), "array index must not begin with '0'");
// error with incorrect numbers
CHECK_THROWS_AS(j["/one"_json_pointer] = 1, std::invalid_argument);
// assign to "-"
j["/-"_json_pointer] = 99;
CHECK(j == json({1, 13, 3, 33, nullptr, 55, 99}));
// error when using "-" in const object
CHECK_THROWS_AS(j_const["/-"_json_pointer], std::out_of_range);
CHECK_THROWS_WITH(j_const["/-"_json_pointer], "array index '-' (3) is out of range");
// error when using "-" with at
CHECK_THROWS_AS(j.at("/-"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j.at("/-"_json_pointer), "array index '-' (7) is out of range");
CHECK_THROWS_AS(j_const.at("/-"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), "array index '-' (3) is out of range");
}
SECTION("const access")
{
const json j = {1, 2, 3};
// check reading access
CHECK(j["/0"_json_pointer] == j[0]);
CHECK(j["/1"_json_pointer] == j[1]);
CHECK(j["/2"_json_pointer] == j[2]);
// assign to nonexisting index
CHECK_THROWS_AS(j.at("/3"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j.at("/3"_json_pointer), "array index 3 is out of range");
// assign to nonexisting index (with gap)
CHECK_THROWS_AS(j.at("/5"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j.at("/5"_json_pointer), "array index 5 is out of range");
// assign to "-"
CHECK_THROWS_AS(j["/-"_json_pointer], std::out_of_range);
CHECK_THROWS_WITH(j["/-"_json_pointer], "array index '-' (3) is out of range");
CHECK_THROWS_AS(j.at("/-"_json_pointer), std::out_of_range);
CHECK_THROWS_WITH(j.at("/-"_json_pointer), "array index '-' (3) is out of range");
}
}
SECTION("flatten")
{
json j =
{
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{
"answer", {
{"everything", 42}
}
},
{"list", {1, 0, 2}},
{
"object", {
{"currency", "USD"},
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
json j_flatten =
{
{"/pi", 3.141},
{"/happy", true},
{"/name", "Niels"},
{"/nothing", nullptr},
{"/answer/everything", 42},
{"/list/0", 1},
{"/list/1", 0},
{"/list/2", 2},
{"/object/currency", "USD"},
{"/object/value", 42.99},
{"/object/", "empty string"},
{"/object/~1", "slash"},
{"/object/~0", "tilde"},
{"/object/~01", "tilde1"}
};
// check if flattened result is as expected
CHECK(j.flatten() == j_flatten);
// check if unflattened result is as expected
CHECK(j_flatten.unflatten() == j);
// error for nonobjects
CHECK_THROWS_AS(json(1).unflatten(), std::domain_error);
CHECK_THROWS_WITH(json(1).unflatten(), "only objects can be unflattened");
// error for nonprimitve values
CHECK_THROWS_AS(json({{"/1", {1, 2, 3}}}).unflatten(), std::domain_error);
CHECK_THROWS_WITH(json({{"/1", {1, 2, 3}}}).unflatten(), "values in object must be primitive");
// error for conflicting values
json j_error = {{"", 42}, {"/foo", 17}};
CHECK_THROWS_AS(j_error.unflatten(), std::domain_error);
CHECK_THROWS_WITH(j_error.unflatten(), "invalid value to unflatten");
// explicit roundtrip check
CHECK(j.flatten().unflatten() == j);
// roundtrip for primitive values
json j_null;
CHECK(j_null.flatten().unflatten() == j_null);
json j_number = 42;
CHECK(j_number.flatten().unflatten() == j_number);
json j_boolean = false;
CHECK(j_boolean.flatten().unflatten() == j_boolean);
json j_string = "foo";
CHECK(j_string.flatten().unflatten() == j_string);
// roundtrip for empty structured values (will be unflattened to null)
json j_array(json::value_t::array);
CHECK(j_array.flatten().unflatten() == json());
json j_object(json::value_t::object);
CHECK(j_object.flatten().unflatten() == json());
}
SECTION("string representation")
{
for (auto ptr :
{"", "/foo", "/foo/0", "/", "/a~1b", "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n"
})
{
CHECK(json::json_pointer(ptr).to_string() == ptr);
}
}
}

713
test/src/unit-modifiers.cpp Normal file
View File

@ -0,0 +1,713 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("modifiers")
{
SECTION("clear()")
{
SECTION("boolean")
{
json j = true;
j.clear();
CHECK(j == json(json::value_t::boolean));
}
SECTION("string")
{
json j = "hello world";
j.clear();
CHECK(j == json(json::value_t::string));
}
SECTION("array")
{
SECTION("empty array")
{
json j = json::array();
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::array));
}
SECTION("filled array")
{
json j = {1, 2, 3};
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::array));
}
}
SECTION("object")
{
SECTION("empty object")
{
json j = json::object();
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::object));
}
SECTION("filled object")
{
json j = {{"one", 1}, {"two", 2}, {"three", 3}};
j.clear();
CHECK(j.empty());
CHECK(j == json(json::value_t::object));
}
}
SECTION("number (integer)")
{
json j = 23;
j.clear();
CHECK(j == json(json::value_t::number_integer));
}
SECTION("number (unsigned)")
{
json j = 23u;
j.clear();
CHECK(j == json(json::value_t::number_integer));
}
SECTION("number (float)")
{
json j = 23.42;
j.clear();
CHECK(j == json(json::value_t::number_float));
}
SECTION("null")
{
json j = nullptr;
j.clear();
CHECK(j == json(json::value_t::null));
}
}
SECTION("push_back()")
{
SECTION("to array")
{
SECTION("json&&")
{
SECTION("null")
{
json j;
j.push_back(1);
j.push_back(2);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2}));
}
SECTION("array")
{
json j = {1, 2, 3};
j.push_back("Hello");
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
CHECK_THROWS_AS(j.push_back("Hello"), std::domain_error);
CHECK_THROWS_WITH(j.push_back("Hello"), "cannot use push_back() with number");
}
}
SECTION("const json&")
{
SECTION("null")
{
json j;
json k(1);
j.push_back(k);
j.push_back(k);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 1}));
}
SECTION("array")
{
json j = {1, 2, 3};
json k("Hello");
j.push_back(k);
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j.push_back(k), std::domain_error);
CHECK_THROWS_WITH(j.push_back(k), "cannot use push_back() with number");
}
}
}
SECTION("to object")
{
SECTION("null")
{
json j;
j.push_back(json::object_t::value_type({"one", 1}));
j.push_back(json::object_t::value_type({"two", 2}));
CHECK(j.type() == json::value_t::object);
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("object")
{
json j(json::value_t::object);
j.push_back(json::object_t::value_type({"one", 1}));
j.push_back(json::object_t::value_type({"two", 2}));
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j.push_back(json::object_t::value_type({"one", 1})), std::domain_error);
CHECK_THROWS_WITH(j.push_back(json::object_t::value_type({"one", 1})),
"cannot use push_back() with number");
}
}
SECTION("with initializer_list")
{
SECTION("null")
{
json j;
j.push_back({"foo", "bar"});
CHECK(j == json::array({{"foo", "bar"}}));
json k;
k.push_back({1, 2, 3});
CHECK(k == json::array({{1, 2, 3}}));
}
SECTION("array")
{
json j = {1, 2, 3};
j.push_back({"foo", "bar"});
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
json k = {1, 2, 3};
k.push_back({1, 2, 3});
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
}
SECTION("object")
{
json j = {{"key1", 1}};
j.push_back({"key2", "bar"});
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
json k = {{"key1", 1}};
CHECK_THROWS_AS(k.push_back({1, 2, 3, 4}), std::domain_error);
CHECK_THROWS_WITH(k.push_back({1, 2, 3, 4}), "cannot use push_back() with object");
}
}
}
SECTION("operator+=")
{
SECTION("to array")
{
SECTION("json&&")
{
SECTION("null")
{
json j;
j += 1;
j += 2;
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2}));
}
SECTION("array")
{
json j = {1, 2, 3};
j += "Hello";
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
CHECK_THROWS_AS(j += "Hello", std::domain_error);
CHECK_THROWS_WITH(j += "Hello", "cannot use push_back() with number");
}
}
SECTION("const json&")
{
SECTION("null")
{
json j;
json k(1);
j += k;
j += k;
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 1}));
}
SECTION("array")
{
json j = {1, 2, 3};
json k("Hello");
j += k;
CHECK(j.type() == json::value_t::array);
CHECK(j == json({1, 2, 3, "Hello"}));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j += k, std::domain_error);
CHECK_THROWS_WITH(j += k, "cannot use push_back() with number");
}
}
}
SECTION("to object")
{
SECTION("null")
{
json j;
j += json::object_t::value_type({"one", 1});
j += json::object_t::value_type({"two", 2});
CHECK(j.type() == json::value_t::object);
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("object")
{
json j(json::value_t::object);
j += json::object_t::value_type({"one", 1});
j += json::object_t::value_type({"two", 2});
CHECK(j.size() == 2);
CHECK(j["one"] == json(1));
CHECK(j["two"] == json(2));
}
SECTION("other type")
{
json j = 1;
json k("Hello");
CHECK_THROWS_AS(j += json::object_t::value_type({"one", 1}), std::domain_error);
CHECK_THROWS_WITH(j += json::object_t::value_type({"one", 1}),
"cannot use push_back() with number");
}
}
SECTION("with initializer_list")
{
SECTION("null")
{
json j;
j += {"foo", "bar"};
CHECK(j == json::array({{"foo", "bar"}}));
json k;
k += {1, 2, 3};
CHECK(k == json::array({{1, 2, 3}}));
}
SECTION("array")
{
json j = {1, 2, 3};
j += {"foo", "bar"};
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
json k = {1, 2, 3};
k += {1, 2, 3};
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
}
SECTION("object")
{
json j = {{"key1", 1}};
j += {"key2", "bar"};
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
json k = {{"key1", 1}};
CHECK_THROWS_AS((k += {1, 2, 3, 4}), std::domain_error);
CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "cannot use push_back() with object");
}
}
}
SECTION("insert")
{
json j_array = {1, 2, 3, 4};
json j_value = 5;
SECTION("value at position")
{
SECTION("insert before begin()")
{
auto it = j_array.insert(j_array.begin(), j_value);
CHECK(j_array.size() == 5);
CHECK(*it == j_value);
CHECK(j_array.begin() == it);
CHECK(j_array == json({5, 1, 2, 3, 4}));
}
SECTION("insert in the middle")
{
auto it = j_array.insert(j_array.begin() + 2, j_value);
CHECK(j_array.size() == 5);
CHECK(*it == j_value);
CHECK((it - j_array.begin()) == 2);
CHECK(j_array == json({1, 2, 5, 3, 4}));
}
SECTION("insert before end()")
{
auto it = j_array.insert(j_array.end(), j_value);
CHECK(j_array.size() == 5);
CHECK(*it == j_value);
CHECK((j_array.end() - it) == 1);
CHECK(j_array == json({1, 2, 3, 4, 5}));
}
}
SECTION("rvalue at position")
{
SECTION("insert before begin()")
{
auto it = j_array.insert(j_array.begin(), 5);
CHECK(j_array.size() == 5);
CHECK(*it == j_value);
CHECK(j_array.begin() == it);
CHECK(j_array == json({5, 1, 2, 3, 4}));
}
SECTION("insert in the middle")
{
auto it = j_array.insert(j_array.begin() + 2, 5);
CHECK(j_array.size() == 5);
CHECK(*it == j_value);
CHECK((it - j_array.begin()) == 2);
CHECK(j_array == json({1, 2, 5, 3, 4}));
}
SECTION("insert before end()")
{
auto it = j_array.insert(j_array.end(), 5);
CHECK(j_array.size() == 5);
CHECK(*it == j_value);
CHECK((j_array.end() - it) == 1);
CHECK(j_array == json({1, 2, 3, 4, 5}));
}
}
SECTION("copies at position")
{
SECTION("insert before begin()")
{
auto it = j_array.insert(j_array.begin(), 3, 5);
CHECK(j_array.size() == 7);
CHECK(*it == j_value);
CHECK(j_array.begin() == it);
CHECK(j_array == json({5, 5, 5, 1, 2, 3, 4}));
}
SECTION("insert in the middle")
{
auto it = j_array.insert(j_array.begin() + 2, 3, 5);
CHECK(j_array.size() == 7);
CHECK(*it == j_value);
CHECK((it - j_array.begin()) == 2);
CHECK(j_array == json({1, 2, 5, 5, 5, 3, 4}));
}
SECTION("insert before end()")
{
auto it = j_array.insert(j_array.end(), 3, 5);
CHECK(j_array.size() == 7);
CHECK(*it == j_value);
CHECK((j_array.end() - it) == 3);
CHECK(j_array == json({1, 2, 3, 4, 5, 5, 5}));
}
SECTION("insert nothing (count = 0)")
{
auto pos = j_array.end();
auto it = j_array.insert(j_array.end(), 0, 5);
CHECK(j_array.size() == 4);
CHECK(it == pos);
CHECK(j_array == json({1, 2, 3, 4}));
}
}
SECTION("range")
{
json j_other_array = {"first", "second"};
SECTION("proper usage")
{
auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.end());
CHECK(j_array.size() == 6);
CHECK(*it == *j_other_array.begin());
CHECK((j_array.end() - it) == 2);
CHECK(j_array == json({1, 2, 3, 4, "first", "second"}));
}
SECTION("empty range")
{
auto it = j_array.insert(j_array.end(), j_other_array.begin(), j_other_array.begin());
CHECK(j_array.size() == 4);
CHECK(it == j_array.end());
CHECK(j_array == json({1, 2, 3, 4}));
}
SECTION("invalid iterators")
{
json j_other_array2 = {"first", "second"};
CHECK_THROWS_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), std::domain_error);
CHECK_THROWS_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()),
std::domain_error);
CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_array.begin(), j_array.end()),
"passed iterators may not belong to container");
CHECK_THROWS_WITH(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()),
"iterators do not fit");
}
}
SECTION("initializer list at position")
{
SECTION("insert before begin()")
{
auto it = j_array.insert(j_array.begin(), {7, 8, 9});
CHECK(j_array.size() == 7);
CHECK(*it == json(7));
CHECK(j_array.begin() == it);
CHECK(j_array == json({7, 8, 9, 1, 2, 3, 4}));
}
SECTION("insert in the middle")
{
auto it = j_array.insert(j_array.begin() + 2, {7, 8, 9});
CHECK(j_array.size() == 7);
CHECK(*it == json(7));
CHECK((it - j_array.begin()) == 2);
CHECK(j_array == json({1, 2, 7, 8, 9, 3, 4}));
}
SECTION("insert before end()")
{
auto it = j_array.insert(j_array.end(), {7, 8, 9});
CHECK(j_array.size() == 7);
CHECK(*it == json(7));
CHECK((j_array.end() - it) == 3);
CHECK(j_array == json({1, 2, 3, 4, 7, 8, 9}));
}
}
SECTION("invalid iterator")
{
// pass iterator to a different array
json j_another_array = {1, 2};
json j_yet_another_array = {"first", "second"};
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10), std::domain_error);
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_value), std::domain_error);
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), 10, 11), std::domain_error);
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), j_yet_another_array.begin(),
j_yet_another_array.end()), std::domain_error);
CHECK_THROWS_AS(j_array.insert(j_another_array.end(), {1, 2, 3, 4}), std::domain_error);
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10), "iterator does not fit current value");
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_value),
"iterator does not fit current value");
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), 10, 11),
"iterator does not fit current value");
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), j_yet_another_array.begin(),
j_yet_another_array.end()), "iterator does not fit current value");
CHECK_THROWS_WITH(j_array.insert(j_another_array.end(), {1, 2, 3, 4}),
"iterator does not fit current value");
}
SECTION("non-array type")
{
// call insert on a non-array type
json j_nonarray = 3;
json j_yet_another_array = {"first", "second"};
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10), std::domain_error);
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_value), std::domain_error);
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), 10, 11), std::domain_error);
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(),
j_yet_another_array.end()), std::domain_error);
CHECK_THROWS_AS(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}), std::domain_error);
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10), "cannot use insert() with number");
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_value), "cannot use insert() with number");
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), 10, 11), "cannot use insert() with number");
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), j_yet_another_array.begin(),
j_yet_another_array.end()), "cannot use insert() with number");
CHECK_THROWS_WITH(j_nonarray.insert(j_nonarray.end(), {1, 2, 3, 4}),
"cannot use insert() with number");
}
}
SECTION("swap()")
{
SECTION("json")
{
SECTION("member swap")
{
json j("hello world");
json k(42.23);
j.swap(k);
CHECK(j == json(42.23));
CHECK(k == json("hello world"));
}
SECTION("nonmember swap")
{
json j("hello world");
json k(42.23);
std::swap(j, k);
CHECK(j == json(42.23));
CHECK(k == json("hello world"));
}
}
SECTION("array_t")
{
SECTION("array_t type")
{
json j = {1, 2, 3, 4};
json::array_t a = {"foo", "bar", "baz"};
j.swap(a);
CHECK(j == json({"foo", "bar", "baz"}));
j.swap(a);
CHECK(j == json({1, 2, 3, 4}));
}
SECTION("non-array_t type")
{
json j = 17;
json::array_t a = {"foo", "bar", "baz"};
CHECK_THROWS_AS(j.swap(a), std::domain_error);
CHECK_THROWS_WITH(j.swap(a), "cannot use swap() with number");
}
}
SECTION("object_t")
{
SECTION("object_t type")
{
json j = {{"one", 1}, {"two", 2}};
json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
j.swap(o);
CHECK(j == json({{"cow", "Kuh"}, {"chicken", "Huhn"}}));
j.swap(o);
CHECK(j == json({{"one", 1}, {"two", 2}}));
}
SECTION("non-object_t type")
{
json j = 17;
json::object_t o = {{"cow", "Kuh"}, {"chicken", "Huhn"}};
CHECK_THROWS_AS(j.swap(o), std::domain_error);
CHECK_THROWS_WITH(j.swap(o), "cannot use swap() with number");
}
}
SECTION("string_t")
{
SECTION("string_t type")
{
json j = "Hello world";
json::string_t s = "Hallo Welt";
j.swap(s);
CHECK(j == json("Hallo Welt"));
j.swap(s);
CHECK(j == json("Hello world"));
}
SECTION("non-string_t type")
{
json j = 17;
json::string_t s = "Hallo Welt";
CHECK_THROWS_AS(j.swap(s), std::domain_error);
CHECK_THROWS_WITH(j.swap(s), "cannot use swap() with number");
}
}
}
}

View File

@ -0,0 +1,443 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("pointer access")
{
// create a JSON value with different types
json json_types =
{
{"boolean", true},
{
"number", {
{"integer", 42},
{"unsigned", 42u},
{"floating-point", 17.23}
}
},
{"string", "Hello, world!"},
{"array", {1, 2, 3, 4, 5}},
{"null", nullptr}
};
SECTION("pointer access to object_t")
{
using test_type = json::object_t;
json value = {{"one", 1}, {"two", 2}};
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() != nullptr);
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
}
SECTION("pointer access to const object_t")
{
using test_type = const json::object_t;
const json value = {{"one", 1}, {"two", 2}};
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() != nullptr);
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
}
SECTION("pointer access to array_t")
{
using test_type = json::array_t;
json value = {1, 2, 3, 4};
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() == nullptr);
CHECK(value.get_ptr<json::array_t*>() != nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
}
SECTION("pointer access to const array_t")
{
using test_type = const json::array_t;
const json value = {1, 2, 3, 4};
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
CHECK(value.get_ptr<const json::array_t*>() != nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
}
SECTION("pointer access to string_t")
{
using test_type = json::string_t;
json value = "hello";
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() == nullptr);
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() != nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
}
SECTION("pointer access to const string_t")
{
using test_type = const json::string_t;
const json value = "hello";
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() != nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
}
SECTION("pointer access to boolean_t")
{
using test_type = json::boolean_t;
json value = false;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() == nullptr);
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() != nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
}
SECTION("pointer access to const boolean_t")
{
using test_type = const json::boolean_t;
const json value = false;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
//CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
//CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
//CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() != nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
}
SECTION("pointer access to number_integer_t")
{
using test_type = json::number_integer_t;
json value = 23;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() == nullptr);
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() != nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
}
SECTION("pointer access to const number_integer_t")
{
using test_type = const json::number_integer_t;
const json value = 23;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() != nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
}
SECTION("pointer access to number_unsigned_t")
{
using test_type = json::number_unsigned_t;
json value = 23u;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() == nullptr);
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() != nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() != nullptr);
CHECK(value.get_ptr<json::number_float_t*>() == nullptr);
}
SECTION("pointer access to const number_unsigned_t")
{
using test_type = const json::number_unsigned_t;
const json value = 23u;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == value.get<test_type>());
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == value.get<test_type>());
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == value.get<test_type>());
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() != nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() != nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() == nullptr);
}
SECTION("pointer access to number_float_t")
{
using test_type = json::number_float_t;
json value = 42.23;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == Approx(value.get<test_type>()));
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == Approx(value.get<test_type>()));
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == Approx(value.get<test_type>()));
// check if null pointers are returned correctly
CHECK(value.get_ptr<json::object_t*>() == nullptr);
CHECK(value.get_ptr<json::array_t*>() == nullptr);
CHECK(value.get_ptr<json::string_t*>() == nullptr);
CHECK(value.get_ptr<json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<json::number_float_t*>() != nullptr);
}
SECTION("pointer access to const number_float_t")
{
using test_type = const json::number_float_t;
const json value = 42.23;
// check if pointers are returned correctly
test_type* p1 = value.get_ptr<test_type*>();
CHECK(p1 == value.get_ptr<test_type*>());
CHECK(*p1 == Approx(value.get<test_type>()));
const test_type* p2 = value.get_ptr<const test_type*>();
CHECK(p1 == value.get_ptr<const test_type*>());
CHECK(*p2 == Approx(value.get<test_type>()));
const test_type* const p3 = value.get_ptr<const test_type* const>();
CHECK(p1 == value.get_ptr<const test_type* const>());
CHECK(*p3 == Approx(value.get<test_type>()));
// check if null pointers are returned correctly
CHECK(value.get_ptr<const json::object_t*>() == nullptr);
CHECK(value.get_ptr<const json::array_t*>() == nullptr);
CHECK(value.get_ptr<const json::string_t*>() == nullptr);
CHECK(value.get_ptr<const json::boolean_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_integer_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_unsigned_t*>() == nullptr);
CHECK(value.get_ptr<const json::number_float_t*>() != nullptr);
}
}

299
test/src/unit-readme.cpp Normal file
View File

@ -0,0 +1,299 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
#include <deque>
#include <forward_list>
#include <list>
#include <unordered_map>
#include <unordered_set>
TEST_CASE("README", "[hide]")
{
{
// redirect std::cout for the README file
auto old_cout_buffer = std::cout.rdbuf();
std::ostringstream new_stream;
std::cout.rdbuf(new_stream.rdbuf());
{
// create an empty structure (null)
json j;
// add a number that is stored as double (note the implicit conversion of j to an object)
j["pi"] = 3.141;
// add a Boolean that is stored as bool
j["happy"] = true;
// add a string that is stored as std::string
j["name"] = "Niels";
// add another null object by passing nullptr
j["nothing"] = nullptr;
// add an object inside the object
j["answer"]["everything"] = 42;
// add an array that is stored as std::vector (using an initializer list)
j["list"] = { 1, 0, 2 };
// add another object (using an initializer list of pairs)
j["object"] = { {"currency", "USD"}, {"value", 42.99} };
// instead, you could also write (which looks very similar to the JSON above)
json j2 =
{
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{
"answer", {
{"everything", 42}
}
},
{"list", {1, 0, 2}},
{
"object", {
{"currency", "USD"},
{"value", 42.99}
}
}
};
}
{
// ways to express the empty array []
json empty_array_implicit = {{}};
json empty_array_explicit = json::array();
// a way to express the empty object {}
json empty_object_explicit = json::object();
// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
json array_not_object = { json::array({"currency", "USD"}), json::array({"value", 42.99}) };
}
{
// create object from string literal
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
// or even nicer with a raw string literal
auto j2 = R"(
{
"happy": true,
"pi": 3.141
}
)"_json;
// or explicitly
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
// explicit conversion to string
std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141}
// serialization with pretty printing
// pass in the amount of spaces to indent
std::cout << j.dump(4) << std::endl;
// {
// "happy": true,
// "pi": 3.141
// }
std::cout << std::setw(2) << j << std::endl;
}
{
// create an array using push_back
json j;
j.push_back("foo");
j.push_back(1);
j.push_back(true);
// iterate the array
for (json::iterator it = j.begin(); it != j.end(); ++it)
{
std::cout << *it << '\n';
}
// range-based for
for (auto element : j)
{
std::cout << element << '\n';
}
// getter/setter
const std::string tmp = j[0];
j[1] = 42;
bool foo = j.at(2);
// other stuff
j.size(); // 3 entries
j.empty(); // false
j.type(); // json::value_t::array
j.clear(); // the array is empty again
// comparison
j == "[\"foo\", 1, true]"_json; // true
// create an object
json o;
o["foo"] = 23;
o["bar"] = false;
o["baz"] = 3.141;
// find an entry
if (o.find("foo") != o.end())
{
// there is an entry with key "foo"
}
}
{
std::vector<int> c_vector {1, 2, 3, 4};
json j_vec(c_vector);
// [1, 2, 3, 4]
std::deque<float> c_deque {1.2f, 2.3f, 3.4f, 5.6f};
json j_deque(c_deque);
// [1.2, 2.3, 3.4, 5.6]
std::list<bool> c_list {true, true, false, true};
json j_list(c_list);
// [true, true, false, true]
std::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};
json j_flist(c_flist);
// [12345678909876, 23456789098765, 34567890987654, 45678909876543]
std::array<unsigned long, 4> c_array {{1, 2, 3, 4}};
json j_array(c_array);
// [1, 2, 3, 4]
std::set<std::string> c_set {"one", "two", "three", "four", "one"};
json j_set(c_set); // only one entry for "one" is used
// ["four", "one", "three", "two"]
std::unordered_set<std::string> c_uset {"one", "two", "three", "four", "one"};
json j_uset(c_uset); // only one entry for "one" is used
// maybe ["two", "three", "four", "one"]
std::multiset<std::string> c_mset {"one", "two", "one", "four"};
json j_mset(c_mset); // only one entry for "one" is used
// maybe ["one", "two", "four"]
std::unordered_multiset<std::string> c_umset {"one", "two", "one", "four"};
json j_umset(c_umset); // both entries for "one" are used
// maybe ["one", "two", "one", "four"]
}
{
std::map<std::string, int> c_map { {"one", 1}, {"two", 2}, {"three", 3} };
json j_map(c_map);
// {"one": 1, "two": 2, "three": 3}
std::unordered_map<const char*, float> c_umap { {"one", 1.2f}, {"two", 2.3f}, {"three", 3.4f} };
json j_umap(c_umap);
// {"one": 1.2, "two": 2.3, "three": 3.4}
std::multimap<std::string, bool> c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
json j_mmap(c_mmap); // only one entry for key "three" is used
// maybe {"one": true, "two": true, "three": true}
std::unordered_multimap<std::string, bool> c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} };
json j_ummap(c_ummap); // only one entry for key "three" is used
// maybe {"one": true, "two": true, "three": true}
}
{
// strings
std::string s1 = "Hello, world!";
json js = s1;
std::string s2 = js;
// Booleans
bool b1 = true;
json jb = b1;
bool b2 = jb;
// numbers
int i = 42;
json jn = i;
double f = jn;
// etc.
std::string vs = js.get<std::string>();
bool vb = jb.get<bool>();
int vi = jn.get<int>();
// etc.
}
{
// a JSON value
json j_original = R"({
"baz": ["one", "two", "three"],
"foo": "bar"
})"_json;
// access members with a JSON pointer (RFC 6901)
j_original["/baz/1"_json_pointer];
// "two"
// a JSON patch (RFC 6902)
json j_patch = R"([
{ "op": "replace", "path": "/baz", "value": "boo" },
{ "op": "add", "path": "/hello", "value": ["world"] },
{ "op": "remove", "path": "/foo"}
])"_json;
// apply the patch
json j_result = j_original.patch(j_patch);
// {
// "baz": "boo",
// "hello": ["world"]
// }
// calculate a JSON patch from two JSON values
json::diff(j_result, j_original);
// [
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
// { "op":"remove","path":"/hello" },
// { "op":"add","path":"/foo","value":"bar" }
// ]
}
// restore old std::cout
std::cout.rdbuf(old_cout_buffer);
}
}

View File

@ -0,0 +1,202 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("reference access")
{
// create a JSON value with different types
json json_types =
{
{"boolean", true},
{
"number", {
{"integer", 42},
{"floating-point", 17.23}
}
},
{"string", "Hello, world!"},
{"array", {1, 2, 3, 4, 5}},
{"null", nullptr}
};
SECTION("reference access to object_t")
{
using test_type = json::object_t;
json value = {{"one", 1}, {"two", 2}};
// check if references are returned correctly
test_type& p1 = value.get_ref<test_type&>();
CHECK(&p1 == value.get_ptr<test_type*>());
CHECK(p1 == value.get<test_type>());
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
// check if mismatching references throw correctly
CHECK_NOTHROW(value.get_ref<json::object_t&>());
CHECK_THROWS(value.get_ref<json::array_t&>());
CHECK_THROWS(value.get_ref<json::string_t&>());
CHECK_THROWS(value.get_ref<json::boolean_t&>());
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
CHECK_THROWS(value.get_ref<json::number_float_t&>());
}
SECTION("const reference access to const object_t")
{
using test_type = json::object_t;
const json value = {{"one", 1}, {"two", 2}};
// this should not compile
// test_type& p1 = value.get_ref<test_type&>();
// check if references are returned correctly
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
}
SECTION("reference access to array_t")
{
using test_type = json::array_t;
json value = {1, 2, 3, 4};
// check if references are returned correctly
test_type& p1 = value.get_ref<test_type&>();
CHECK(&p1 == value.get_ptr<test_type*>());
CHECK(p1 == value.get<test_type>());
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
// check if mismatching references throw correctly
CHECK_THROWS(value.get_ref<json::object_t&>());
CHECK_NOTHROW(value.get_ref<json::array_t&>());
CHECK_THROWS(value.get_ref<json::string_t&>());
CHECK_THROWS(value.get_ref<json::boolean_t&>());
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
CHECK_THROWS(value.get_ref<json::number_float_t&>());
}
SECTION("reference access to string_t")
{
using test_type = json::string_t;
json value = "hello";
// check if references are returned correctly
test_type& p1 = value.get_ref<test_type&>();
CHECK(&p1 == value.get_ptr<test_type*>());
CHECK(p1 == value.get<test_type>());
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
// check if mismatching references throw correctly
CHECK_THROWS(value.get_ref<json::object_t&>());
CHECK_THROWS(value.get_ref<json::array_t&>());
CHECK_NOTHROW(value.get_ref<json::string_t&>());
CHECK_THROWS(value.get_ref<json::boolean_t&>());
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
CHECK_THROWS(value.get_ref<json::number_float_t&>());
}
SECTION("reference access to boolean_t")
{
using test_type = json::boolean_t;
json value = false;
// check if references are returned correctly
test_type& p1 = value.get_ref<test_type&>();
CHECK(&p1 == value.get_ptr<test_type*>());
CHECK(p1 == value.get<test_type>());
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
// check if mismatching references throw correctly
CHECK_THROWS(value.get_ref<json::object_t&>());
CHECK_THROWS(value.get_ref<json::array_t&>());
CHECK_THROWS(value.get_ref<json::string_t&>());
CHECK_NOTHROW(value.get_ref<json::boolean_t&>());
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
CHECK_THROWS(value.get_ref<json::number_float_t&>());
}
SECTION("reference access to number_integer_t")
{
using test_type = json::number_integer_t;
json value = 23;
// check if references are returned correctly
test_type& p1 = value.get_ref<test_type&>();
CHECK(&p1 == value.get_ptr<test_type*>());
CHECK(p1 == value.get<test_type>());
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
// check if mismatching references throw correctly
CHECK_THROWS(value.get_ref<json::object_t&>());
CHECK_THROWS(value.get_ref<json::array_t&>());
CHECK_THROWS(value.get_ref<json::string_t&>());
CHECK_THROWS(value.get_ref<json::boolean_t&>());
CHECK_NOTHROW(value.get_ref<json::number_integer_t&>());
CHECK_THROWS(value.get_ref<json::number_float_t&>());
}
SECTION("reference access to number_float_t")
{
using test_type = json::number_float_t;
json value = 42.23;
// check if references are returned correctly
test_type& p1 = value.get_ref<test_type&>();
CHECK(&p1 == value.get_ptr<test_type*>());
CHECK(p1 == value.get<test_type>());
const test_type& p2 = value.get_ref<const test_type&>();
CHECK(&p2 == value.get_ptr<const test_type*>());
CHECK(p2 == value.get<test_type>());
// check if mismatching references throw correctly
CHECK_THROWS(value.get_ref<json::object_t&>());
CHECK_THROWS(value.get_ref<json::array_t&>());
CHECK_THROWS(value.get_ref<json::string_t&>());
CHECK_THROWS(value.get_ref<json::boolean_t&>());
CHECK_THROWS(value.get_ref<json::number_integer_t&>());
CHECK_NOTHROW(value.get_ref<json::number_float_t&>());
}
}

View File

@ -0,0 +1,443 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("regression tests")
{
SECTION("issue #60 - Double quotation mark is not parsed correctly")
{
SECTION("escape_dobulequote")
{
auto s = "[\"\\\"foo\\\"\"]";
json j = json::parse(s);
auto expected = R"(["\"foo\""])"_json;
CHECK(j == expected);
}
}
SECTION("issue #70 - Handle infinity and NaN cases")
{
SECTION("NAN value")
{
CHECK(json(NAN) == json());
CHECK(json(json::number_float_t(NAN)) == json());
}
SECTION("infinity")
{
CHECK(json(INFINITY) == json());
CHECK(json(json::number_float_t(INFINITY)) == json());
}
}
SECTION("pull request #71 - handle enum type")
{
enum { t = 0 };
json j = json::array();
j.push_back(t);
j.push_back(json::object(
{
{"game_type", t}
}));
}
SECTION("issue #76 - dump() / parse() not idempotent")
{
// create JSON object
json fields;
fields["one"] = std::string("one");
fields["two"] = std::string("two three");
fields["three"] = std::string("three \"four\"");
// create another JSON object by deserializing the serialization
std::string payload = fields.dump();
json parsed_fields = json::parse(payload);
// check individual fields to match both objects
CHECK(parsed_fields["one"] == fields["one"]);
CHECK(parsed_fields["two"] == fields["two"]);
CHECK(parsed_fields["three"] == fields["three"]);
// check individual fields to match original input
CHECK(parsed_fields["one"] == std::string("one"));
CHECK(parsed_fields["two"] == std::string("two three"));
CHECK(parsed_fields["three"] == std::string("three \"four\""));
// check equality of the objects
CHECK(parsed_fields == fields);
// check equality of the serialized objects
CHECK(fields.dump() == parsed_fields.dump());
// check everything in one line
CHECK(fields == json::parse(fields.dump()));
}
SECTION("issue #82 - lexer::get_number return NAN")
{
const auto content = R"(
{
"Test":"Test1",
"Number":100,
"Foo":42.42
})";
std::stringstream ss;
ss << content;
json j;
ss >> j;
std::string test = j["Test"];
CHECK(test == "Test1");
int number = j["Number"];
CHECK(number == 100);
float foo = j["Foo"];
CHECK(foo == Approx(42.42));
}
SECTION("issue #89 - nonstandard integer type")
{
// create JSON class with nonstandard integer number type
using custom_json =
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
custom_json j;
j["int_1"] = 1;
// we need to cast to int to compile with Catch - the value is int32_t
CHECK(static_cast<int>(j["int_1"]) == 1);
// tests for correct handling of non-standard integers that overflow the type selected by the user
// unsigned integer object creation - expected to wrap and still be stored as an integer
j = 4294967296U; // 2^32
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_unsigned));
CHECK(j.get<uint32_t>() == 0); // Wrap
// unsigned integer parsing - expected to overflow and be stored as a float
j = custom_json::parse("4294967296"); // 2^32
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
CHECK(j.get<float>() == 4294967296.0f);
// integer object creation - expected to wrap and still be stored as an integer
j = -2147483649LL; // -2^31-1
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_integer));
CHECK(j.get<int32_t>() == 2147483647); // Wrap
// integer parsing - expected to overflow and be stored as a float with rounding
j = custom_json::parse("-2147483649"); // -2^31
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_float));
CHECK(j.get<float>() == -2147483650.0f);
}
SECTION("issue #93 reverse_iterator operator inheritance problem")
{
{
json a = {1, 2, 3};
json::reverse_iterator rit = a.rbegin();
++rit;
CHECK(*rit == json(2));
CHECK(rit.value() == json(2));
}
{
json a = {1, 2, 3};
json::reverse_iterator rit = ++a.rbegin();
}
{
json a = {1, 2, 3};
json::reverse_iterator rit = a.rbegin();
++rit;
json b = {0, 0, 0};
std::transform(rit, a.rend(), b.rbegin(), [](json el)
{
return el;
});
CHECK(b == json({0, 1, 2}));
}
{
json a = {1, 2, 3};
json b = {0, 0, 0};
std::transform(++a.rbegin(), a.rend(), b.rbegin(), [](json el)
{
return el;
});
CHECK(b == json({0, 1, 2}));
}
}
SECTION("issue #100 - failed to iterator json object with reverse_iterator")
{
json config =
{
{ "111", 111 },
{ "112", 112 },
{ "113", 113 }
};
std::stringstream ss;
for (auto it = config.begin(); it != config.end(); ++it)
{
ss << it.key() << ": " << it.value() << '\n';
}
for (auto it = config.rbegin(); it != config.rend(); ++it)
{
ss << it.key() << ": " << it.value() << '\n';
}
CHECK(ss.str() == "111: 111\n112: 112\n113: 113\n113: 113\n112: 112\n111: 111\n");
}
SECTION("issue #101 - binary string causes numbers to be dumped as hex")
{
int64_t number = 10;
std::string bytes{"\x00" "asdf\n", 6};
json j;
j["int64"] = number;
j["binary string"] = bytes;
// make sure the number is really printed as decimal "10" and not as
// hexadecimal "a"
CHECK(j.dump() == "{\"binary string\":\"\\u0000asdf\\n\",\"int64\":10}");
}
SECTION("issue #111 - subsequent unicode chars")
{
std::string bytes{0x7, 0x7};
json j;
j["string"] = bytes;
CHECK(j["string"] == "\u0007\u0007");
}
SECTION("issue #144 - implicit assignment to std::string fails")
{
json o = {{"name", "value"}};
std::string s1 = o["name"];
CHECK(s1 == "value");
std::string s2;
s2 = o["name"];
CHECK(s2 == "value");
}
SECTION("issue #146 - character following a surrogate pair is skipped")
{
CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc");
}
SECTION("issue #171 - Cannot index by key of type static constexpr const char*")
{
json j;
// Non-const access with key as "char []"
char array_key[] = "Key1";
CHECK_NOTHROW(j[array_key] = 1);
CHECK(j[array_key] == json(1));
// Non-const access with key as "const char[]"
const char const_array_key[] = "Key2";
CHECK_NOTHROW(j[const_array_key] = 2);
CHECK(j[const_array_key] == json(2));
// Non-const access with key as "char *"
char _ptr_key[] = "Key3";
char* ptr_key = &_ptr_key[0];
CHECK_NOTHROW(j[ptr_key] = 3);
CHECK(j[ptr_key] == json(3));
// Non-const access with key as "const char *"
const char* const_ptr_key = "Key4";
CHECK_NOTHROW(j[const_ptr_key] = 4);
CHECK(j[const_ptr_key] == json(4));
// Non-const access with key as "static constexpr const char *"
static constexpr const char* constexpr_ptr_key = "Key5";
CHECK_NOTHROW(j[constexpr_ptr_key] = 5);
CHECK(j[constexpr_ptr_key] == json(5));
const json j_const = j;
// Const access with key as "char []"
CHECK(j_const[array_key] == json(1));
// Const access with key as "const char[]"
CHECK(j_const[const_array_key] == json(2));
// Const access with key as "char *"
CHECK(j_const[ptr_key] == json(3));
// Const access with key as "const char *"
CHECK(j_const[const_ptr_key] == json(4));
// Const access with key as "static constexpr const char *"
CHECK(j_const[constexpr_ptr_key] == json(5));
}
SECTION("issue #186 miloyip/nativejson-benchmark: floating-point parsing")
{
json j;
j = json::parse("-0.0");
CHECK(j.get<double>() == -0.0);
j = json::parse("2.22507385850720113605740979670913197593481954635164564e-308");
CHECK(j.get<double>() == 2.2250738585072009e-308);
j = json::parse("0.999999999999999944488848768742172978818416595458984374");
CHECK(j.get<double>() == 0.99999999999999989);
j = json::parse("1.00000000000000011102230246251565404236316680908203126");
CHECK(j.get<double>() == 1.00000000000000022);
j = json::parse("7205759403792793199999e-5");
CHECK(j.get<double>() == 72057594037927928.0);
j = json::parse("922337203685477529599999e-5");
CHECK(j.get<double>() == 9223372036854774784.0);
j = json::parse("1014120480182583464902367222169599999e-5");
CHECK(j.get<double>() == 10141204801825834086073718800384.0);
j = json::parse("5708990770823839207320493820740630171355185151999e-3");
CHECK(j.get<double>() == 5708990770823838890407843763683279797179383808.0);
// create JSON class with nonstandard float number type
// float
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float =
1.23e25f;
CHECK(j_float.get<float>() == 1.23e25f);
// double
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double =
1.23e35f;
CHECK(j_double.get<double>() == 1.23e35f);
// long double
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double>
j_long_double = 1.23e45L;
CHECK(j_long_double.get<long double>() == 1.23e45L);
}
SECTION("issue #228 - double values are serialized with commas as decimal points")
{
json j1a = 23.42;
json j1b = json::parse("23.42");
json j2a = 2342e-2;
//issue #230
//json j2b = json::parse("2342e-2");
json j3a = 10E3;
json j3b = json::parse("10E3");
json j3c = json::parse("10e3");
// class to create a locale that would use a comma for decimals
class CommaDecimalSeparator : public std::numpunct<char>
{
protected:
char do_decimal_point() const
{
return ',';
}
};
// change locale to mess with decimal points
std::locale::global(std::locale(std::locale(), new CommaDecimalSeparator));
CHECK(j1a.dump() == "23.42");
CHECK(j1b.dump() == "23.42");
// check if locale is properly reset
std::stringstream ss;
ss.imbue(std::locale(std::locale(), new CommaDecimalSeparator));
ss << 47.11;
CHECK(ss.str() == "47,11");
ss << j1a;
CHECK(ss.str() == "47,1123.42");
ss << 47.11;
CHECK(ss.str() == "47,1123.4247,11");
CHECK(j2a.dump() == "23.42");
//issue #230
//CHECK(j2b.dump() == "23.42");
CHECK(j3a.dump() == "10000");
CHECK(j3b.dump() == "10000");
CHECK(j3c.dump() == "10000");
//CHECK(j3b.dump() == "1E04"); // roundtrip error
//CHECK(j3c.dump() == "1e04"); // roundtrip error
}
SECTION("issue #233 - Can't use basic_json::iterator as a base iterator for std::move_iterator")
{
json source = {"a", "b", "c"};
json expected = {"a", "b"};
json dest;
std::copy_n(std::make_move_iterator(source.begin()), 2, std::back_inserter(dest));
CHECK(dest == expected);
}
SECTION("issue #235 - ambiguous overload for 'push_back' and 'operator+='")
{
json data = {{"key", "value"}};
data.push_back({"key2", "value2"});
data += {"key3", "value3"};
CHECK(data == json({{"key", "value"}, {"key2", "value2"}, {"key3", "value3"}}));
}
SECTION("issue #269 - diff generates incorrect patch when removing multiple array elements")
{
json doc = R"( { "arr1": [1, 2, 3, 4] } )"_json;
json expected = R"( { "arr1": [1, 2] } )"_json;
// check roundtrip
CHECK(doc.patch(json::diff(doc, expected)) == expected);
}
SECTION("issue #283 - value() does not work with _json_pointer types")
{
json j =
{
{"object", {{"key1", 1}, {"key2", 2}}},
};
int at_integer = j.at("/object/key2"_json_pointer);
int val_integer = j.value("/object/key2"_json_pointer, 0);
CHECK(at_integer == val_integer);
}
}

View File

@ -0,0 +1,76 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
TEST_CASE("serialization")
{
SECTION("operator<<")
{
SECTION("no given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
ss << j;
CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
}
SECTION("given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
ss << std::setw(4) << j;
CHECK(ss.str() ==
"[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
}
}
SECTION("operator>>")
{
SECTION("no given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
j >> ss;
CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
}
SECTION("given width")
{
std::stringstream ss;
json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
ss.width(4);
j >> ss;
CHECK(ss.str() ==
"[\n \"foo\",\n 1,\n 2,\n 3,\n false,\n {\n \"one\": 1\n }\n]");
}
}
}

View File

@ -0,0 +1,436 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#include "json.hpp"
using nlohmann::json;
#include <fstream>
TEST_CASE("compliance tests from json.org")
{
// test cases are from http://json.org/JSON_checker/
SECTION("expected failures")
{
for (auto filename :
{
//"test/data/json_tests/fail1.json",
"test/data/json_tests/fail2.json",
"test/data/json_tests/fail3.json",
"test/data/json_tests/fail4.json",
"test/data/json_tests/fail5.json",
"test/data/json_tests/fail6.json",
"test/data/json_tests/fail7.json",
"test/data/json_tests/fail8.json",
"test/data/json_tests/fail9.json",
"test/data/json_tests/fail10.json",
"test/data/json_tests/fail11.json",
"test/data/json_tests/fail12.json",
"test/data/json_tests/fail13.json",
"test/data/json_tests/fail14.json",
"test/data/json_tests/fail15.json",
"test/data/json_tests/fail16.json",
"test/data/json_tests/fail17.json",
//"test/data/json_tests/fail18.json",
"test/data/json_tests/fail19.json",
"test/data/json_tests/fail20.json",
"test/data/json_tests/fail21.json",
"test/data/json_tests/fail22.json",
"test/data/json_tests/fail23.json",
"test/data/json_tests/fail24.json",
"test/data/json_tests/fail25.json",
"test/data/json_tests/fail26.json",
"test/data/json_tests/fail27.json",
"test/data/json_tests/fail28.json",
"test/data/json_tests/fail29.json",
"test/data/json_tests/fail30.json",
"test/data/json_tests/fail31.json",
"test/data/json_tests/fail32.json",
"test/data/json_tests/fail33.json"
})
{
CAPTURE(filename);
json j;
std::ifstream f(filename);
CHECK_THROWS_AS(j << f, std::invalid_argument);
}
}
SECTION("expected passes")
{
for (auto filename :
{
"test/data/json_tests/pass1.json",
"test/data/json_tests/pass2.json",
"test/data/json_tests/pass3.json"
})
{
CAPTURE(filename);
json j;
std::ifstream f(filename);
CHECK_NOTHROW(j << f);
}
}
}
TEST_CASE("compliance tests from nativejson-benchmark")
{
// test cases from https://github.com/miloyip/nativejson-benchmark/blob/master/src/main.cpp
SECTION("doubles")
{
auto TEST_DOUBLE = [](const std::string & json_string, const double expected)
{
CAPTURE(json_string);
CAPTURE(expected);
CHECK(json::parse(json_string)[0].get<double>() == Approx(expected));
};
TEST_DOUBLE("[0.0]", 0.0);
TEST_DOUBLE("[-0.0]", -0.0);
TEST_DOUBLE("[1.0]", 1.0);
TEST_DOUBLE("[-1.0]", -1.0);
TEST_DOUBLE("[1.5]", 1.5);
TEST_DOUBLE("[-1.5]", -1.5);
TEST_DOUBLE("[3.1416]", 3.1416);
TEST_DOUBLE("[1E10]", 1E10);
TEST_DOUBLE("[1e10]", 1e10);
TEST_DOUBLE("[1E+10]", 1E+10);
TEST_DOUBLE("[1E-10]", 1E-10);
TEST_DOUBLE("[-1E10]", -1E10);
TEST_DOUBLE("[-1e10]", -1e10);
TEST_DOUBLE("[-1E+10]", -1E+10);
TEST_DOUBLE("[-1E-10]", -1E-10);
TEST_DOUBLE("[1.234E+10]", 1.234E+10);
TEST_DOUBLE("[1.234E-10]", 1.234E-10);
TEST_DOUBLE("[1.79769e+308]", 1.79769e+308);
TEST_DOUBLE("[2.22507e-308]", 2.22507e-308);
TEST_DOUBLE("[-1.79769e+308]", -1.79769e+308);
TEST_DOUBLE("[-2.22507e-308]", -2.22507e-308);
TEST_DOUBLE("[4.9406564584124654e-324]", 4.9406564584124654e-324); // minimum denormal
TEST_DOUBLE("[2.2250738585072009e-308]", 2.2250738585072009e-308); // Max subnormal double
TEST_DOUBLE("[2.2250738585072014e-308]", 2.2250738585072014e-308); // Min normal positive double
TEST_DOUBLE("[1.7976931348623157e+308]", 1.7976931348623157e+308); // Max double
TEST_DOUBLE("[1e-10000]", 0.0); // must underflow
TEST_DOUBLE("[18446744073709551616]",
18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double)
TEST_DOUBLE("[-9223372036854775809]",
-9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double)
TEST_DOUBLE("[0.9868011474609375]",
0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120
TEST_DOUBLE("[123e34]", 123e34); // Fast Path Cases In Disguise
TEST_DOUBLE("[45913141877270640000.0]", 45913141877270640000.0);
TEST_DOUBLE("[2.2250738585072011e-308]",
2.2250738585072011e-308);
//TEST_DOUBLE("[1e-00011111111111]", 0.0);
//TEST_DOUBLE("[-1e-00011111111111]", -0.0);
TEST_DOUBLE("[1e-214748363]", 0.0);
TEST_DOUBLE("[1e-214748364]", 0.0);
//TEST_DOUBLE("[1e-21474836311]", 0.0);
TEST_DOUBLE("[0.017976931348623157e+310]", 1.7976931348623157e+308); // Max double in another form
// Since
// abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... ¡Á 10^-324
// abs((2^-1022) - 2.2250738585072012e-308) = 1.830902327173324040642192159804623318305533274168872044... ¡Á 10 ^ -324
// So 2.2250738585072012e-308 should round to 2^-1022 = 2.2250738585072014e-308
TEST_DOUBLE("[2.2250738585072012e-308]",
2.2250738585072014e-308);
// More closer to normal/subnormal boundary
// boundary = 2^-1022 - 2^-1075 = 2.225073858507201136057409796709131975934819546351645648... ¡Á 10^-308
TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164564e-308]",
2.2250738585072009e-308);
TEST_DOUBLE("[2.22507385850720113605740979670913197593481954635164565e-308]",
2.2250738585072014e-308);
// 1.0 is in (1.0 - 2^-54, 1.0 + 2^-53)
// 1.0 - 2^-54 = 0.999999999999999944488848768742172978818416595458984375
TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984375]", 1.0); // round to even
TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984374]",
0.99999999999999989); // previous double
TEST_DOUBLE("[0.999999999999999944488848768742172978818416595458984376]", 1.0); // next double
// 1.0 + 2^-53 = 1.00000000000000011102230246251565404236316680908203125
TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203125]", 1.0); // round to even
TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203124]", 1.0); // previous double
TEST_DOUBLE("[1.00000000000000011102230246251565404236316680908203126]",
1.00000000000000022); // next double
// Numbers from https://github.com/floitsch/double-conversion/blob/master/test/cctest/test-strtod.cc
TEST_DOUBLE("[72057594037927928.0]", 72057594037927928.0);
TEST_DOUBLE("[72057594037927936.0]", 72057594037927936.0);
TEST_DOUBLE("[72057594037927932.0]", 72057594037927936.0);
TEST_DOUBLE("[7205759403792793199999e-5]", 72057594037927928.0);
TEST_DOUBLE("[7205759403792793200001e-5]", 72057594037927936.0);
TEST_DOUBLE("[9223372036854774784.0]", 9223372036854774784.0);
TEST_DOUBLE("[9223372036854775808.0]", 9223372036854775808.0);
TEST_DOUBLE("[9223372036854775296.0]", 9223372036854775808.0);
TEST_DOUBLE("[922337203685477529599999e-5]", 9223372036854774784.0);
TEST_DOUBLE("[922337203685477529600001e-5]", 9223372036854775808.0);
TEST_DOUBLE("[10141204801825834086073718800384]", 10141204801825834086073718800384.0);
TEST_DOUBLE("[10141204801825835211973625643008]", 10141204801825835211973625643008.0);
TEST_DOUBLE("[10141204801825834649023672221696]", 10141204801825835211973625643008.0);
TEST_DOUBLE("[1014120480182583464902367222169599999e-5]", 10141204801825834086073718800384.0);
TEST_DOUBLE("[1014120480182583464902367222169600001e-5]", 10141204801825835211973625643008.0);
TEST_DOUBLE("[5708990770823838890407843763683279797179383808]",
5708990770823838890407843763683279797179383808.0);
TEST_DOUBLE("[5708990770823839524233143877797980545530986496]",
5708990770823839524233143877797980545530986496.0);
TEST_DOUBLE("[5708990770823839207320493820740630171355185152]",
5708990770823839524233143877797980545530986496.0);
TEST_DOUBLE("[5708990770823839207320493820740630171355185151999e-3]",
5708990770823838890407843763683279797179383808.0);
TEST_DOUBLE("[5708990770823839207320493820740630171355185152001e-3]",
5708990770823839524233143877797980545530986496.0);
{
char n1e308[312]; // '1' followed by 308 '0'
n1e308[0] = '[';
n1e308[1] = '1';
for (int j = 2; j < 310; j++)
{
n1e308[j] = '0';
}
n1e308[310] = ']';
n1e308[311] = '\0';
TEST_DOUBLE(n1e308, 1E308);
}
// Cover trimming
TEST_DOUBLE(
"[2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508"
"7914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012"
"9811224514518898490572223072852551331557550159143974763979834118019993239625482890171070818506906306"
"6665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505"
"1080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621"
"5722898802581825451803257070188608721131280795122334262883686223215037756666225039825343359745688844"
"2390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042"
"7567186443383770486037861622771738545623065874679014086723327636718751234567890123456789012345678901"
"e-308]",
2.2250738585072014e-308);
}
SECTION("strings")
{
auto TEST_STRING = [](const std::string & json_string, const std::string & expected)
{
CAPTURE(json_string);
CAPTURE(expected);
CHECK(json::parse(json_string)[0].get<std::string>() == expected);
};
TEST_STRING("[\"\"]", "");
TEST_STRING("[\"Hello\"]", "Hello");
TEST_STRING("[\"Hello\\nWorld\"]", "Hello\nWorld");
//TEST_STRING("[\"Hello\\u0000World\"]", "Hello\0World");
TEST_STRING("[\"\\\"\\\\/\\b\\f\\n\\r\\t\"]", "\"\\/\b\f\n\r\t");
TEST_STRING("[\"\\u0024\"]", "\x24"); // Dollar sign U+0024
TEST_STRING("[\"\\u00A2\"]", "\xC2\xA2"); // Cents sign U+00A2
TEST_STRING("[\"\\u20AC\"]", "\xE2\x82\xAC"); // Euro sign U+20AC
TEST_STRING("[\"\\uD834\\uDD1E\"]", "\xF0\x9D\x84\x9E"); // G clef sign U+1D11E
}
SECTION("roundtrip")
{
// test cases are from https://github.com/miloyip/nativejson-benchmark/tree/master/test/data/roundtrip
for (auto filename :
{
"test/data/json_roundtrip/roundtrip01.json",
"test/data/json_roundtrip/roundtrip02.json",
"test/data/json_roundtrip/roundtrip03.json",
"test/data/json_roundtrip/roundtrip04.json",
"test/data/json_roundtrip/roundtrip05.json",
"test/data/json_roundtrip/roundtrip06.json",
"test/data/json_roundtrip/roundtrip07.json",
"test/data/json_roundtrip/roundtrip08.json",
"test/data/json_roundtrip/roundtrip09.json",
"test/data/json_roundtrip/roundtrip10.json",
"test/data/json_roundtrip/roundtrip11.json",
"test/data/json_roundtrip/roundtrip12.json",
"test/data/json_roundtrip/roundtrip13.json",
"test/data/json_roundtrip/roundtrip14.json",
"test/data/json_roundtrip/roundtrip15.json",
"test/data/json_roundtrip/roundtrip16.json",
"test/data/json_roundtrip/roundtrip17.json",
"test/data/json_roundtrip/roundtrip18.json",
"test/data/json_roundtrip/roundtrip19.json",
"test/data/json_roundtrip/roundtrip20.json",
"test/data/json_roundtrip/roundtrip21.json",
"test/data/json_roundtrip/roundtrip22.json",
"test/data/json_roundtrip/roundtrip23.json",
//"test/data/json_roundtrip/roundtrip24.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip25.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip26.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip27.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip28.json", // roundtrip error
"test/data/json_roundtrip/roundtrip29.json",
//"test/data/json_roundtrip/roundtrip30.json", // roundtrip error
//"test/data/json_roundtrip/roundtrip31.json", // roundtrip error
"test/data/json_roundtrip/roundtrip32.json"
})
{
CAPTURE(filename);
std::ifstream f(filename);
std::string json_string( (std::istreambuf_iterator<char>(f) ),
(std::istreambuf_iterator<char>()) );
json j = json::parse(json_string);
CHECK(j.dump() == json_string);
}
}
}
TEST_CASE("test suite from json-test-suite")
{
SECTION("read all sample.json")
{
// read a file with all unicode characters stored as single-character
// strings in a JSON array
std::ifstream f("test/data/json_testsuite/sample.json");
json j;
CHECK_NOTHROW(j << f);
// the array has 3 elements
CHECK(j.size() == 3);
}
}
TEST_CASE("json.org examples")
{
// here, we list all JSON values from http://json.org/example
SECTION("1.json")
{
std::ifstream f("test/data/json.org/1.json");
json j;
CHECK_NOTHROW(j << f);
}
SECTION("2.json")
{
std::ifstream f("test/data/json.org/2.json");
json j;
CHECK_NOTHROW(j << f);
}
SECTION("3.json")
{
std::ifstream f("test/data/json.org/3.json");
json j;
CHECK_NOTHROW(j << f);
}
SECTION("4.json")
{
std::ifstream f("test/data/json.org/4.json");
json j;
CHECK_NOTHROW(j << f);
}
SECTION("5.json")
{
std::ifstream f("test/data/json.org/5.json");
json j;
CHECK_NOTHROW(j << f);
}
}
TEST_CASE("RFC 7159 examples")
{
// here, we list all JSON values from the RFC 7159 document
SECTION("7. Strings")
{
CHECK(json::parse("\"\\u005C\"") == json("\\"));
CHECK(json::parse("\"\\uD834\\uDD1E\"") == json("𝄞"));
CHECK(json::parse("\"𝄞\"") == json("𝄞"));
}
SECTION("8.3 String Comparison")
{
CHECK(json::parse("\"a\\b\"") == json::parse("\"a\u005Cb\""));
}
SECTION("13 Examples")
{
{
CHECK_NOTHROW(json(R"(
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": 100
},
"Animated" : false,
"IDs": [116, 943, 234, 38793]
}
}
)"));
}
{
CHECK_NOTHROW(json(R"(
[
{
"precision": "zip",
"Latitude": 37.7668,
"Longitude": -122.3959,
"Address": "",
"City": "SAN FRANCISCO",
"State": "CA",
"Zip": "94107",
"Country": "US"
},
{
"precision": "zip",
"Latitude": 37.371991,
"Longitude": -122.026020,
"Address": "",
"City": "SUNNYVALE",
"State": "CA",
"Zip": "94085",
"Country": "US"
}
])"));
}
CHECK(json::parse("\"Hello world!\"") == json("Hello world!"));
CHECK(json::parse("42") == json(42));
CHECK(json::parse("true") == json(true));
}
}

176
test/src/unit-unicode.cpp Normal file
View File

@ -0,0 +1,176 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
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 "catch.hpp"
#define private public
#include "json.hpp"
using nlohmann::json;
#include <fstream>
TEST_CASE("Unicode", "[hide]")
{
SECTION("full enumeration of Unicode code points")
{
// create an escaped string from a code point
const auto codepoint_to_unicode = [](std::size_t cp)
{
// copd points are represented as a six-character sequence: a
// reverse solidus, followed by the lowercase letter u, followed
// by four hexadecimal digits that encode the character's code
// point
std::stringstream ss;
ss << "\\u" << std::setw(4) << std::setfill('0') << std::hex << cp;
return ss.str();
};
// generate all UTF-8 code points; in total, 1112064 code points are
// generated: 0x1FFFFF code points - 2048 invalid values between
// 0xD800 and 0xDFFF.
for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp)
{
// The Unicode standard permanently reserves these code point
// values for UTF-16 encoding of the high and low surrogates, and
// they will never be assigned a character, so there should be no
// reason to encode them. The official Unicode standard says that
// no UTF forms, including UTF-16, can encode these code points.
if (cp >= 0xD800u and cp <= 0xDFFFu)
{
// if we would not skip these code points, we would get a
// "missing low surrogate" exception
continue;
}
// string to store the code point as in \uxxxx format
std::string escaped_string;
// string to store the code point as unescaped character sequence
std::string unescaped_string;
if (cp < 0x10000u)
{
// code points in the Basic Multilingual Plane can be
// represented with one \\uxxxx sequence
escaped_string = codepoint_to_unicode(cp);
// All Unicode characters may be placed within the quotation
// marks, except for the characters that must be escaped:
// quotation mark, reverse solidus, and the control characters
// (U+0000 through U+001F); we ignore these code points as
// they are checked with codepoint_to_unicode.
if (cp > 0x1f and cp != 0x22 and cp != 0x5c)
{
unescaped_string = json::lexer::to_unicode(cp);
}
}
else
{
// To escape an extended character that is not in the Basic
// Multilingual Plane, the character is represented as a
// 12-character sequence, encoding the UTF-16 surrogate pair
const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu);
const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu);
escaped_string = codepoint_to_unicode(codepoint1);
escaped_string += codepoint_to_unicode(codepoint2);
unescaped_string += json::lexer::to_unicode(codepoint1, codepoint2);
}
// all other code points are valid and must not yield parse errors
CAPTURE(cp);
CAPTURE(escaped_string);
CAPTURE(unescaped_string);
json j1, j2, j3, j4;
CHECK_NOTHROW(j1 = json::parse("\"" + escaped_string + "\""));
CHECK_NOTHROW(j2 = json::parse(j1.dump()));
CHECK(j1 == j2);
CHECK_NOTHROW(j3 = json::parse("\"" + unescaped_string + "\""));
CHECK_NOTHROW(j4 = json::parse(j3.dump()));
CHECK(j3 == j4);
}
}
SECTION("read all unicode characters")
{
// read a file with all unicode characters stored as single-character
// strings in a JSON array
std::ifstream f("test/data/json_nlohmann_tests/all_unicode.json");
json j;
CHECK_NOTHROW(j << f);
// the array has 1112064 + 1 elemnts (a terminating "null" value)
// Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between
// 0xD800 and 0xDFFF.
CHECK(j.size() == 1112065);
SECTION("check JSON Pointers")
{
for (auto s : j)
{
// skip non-string JSON values
if (not s.is_string())
{
continue;
}
std::string ptr = s;
// tilde must be followed by 0 or 1
if (ptr == "~")
{
ptr += "0";
}
// JSON Pointers must begin with "/"
ptr = "/" + ptr;
CHECK_NOTHROW(json::json_pointer("/" + ptr));
// check escape/unescape roundtrip
auto escaped = json::json_pointer::escape(ptr);
json::json_pointer::unescape(escaped);
CHECK(escaped == ptr);
}
}
}
SECTION("ignore byte-order-mark")
{
// read a file with a UTF-8 BOM
std::ifstream f("test/data/json_nlohmann_tests/bom.json");
json j;
CHECK_NOTHROW(j << f);
}
SECTION("error for incomplete/wrong BOM")
{
CHECK_THROWS_AS(json::parse("\xef\xbb"), std::invalid_argument);
CHECK_THROWS_AS(json::parse("\xef\xbb\xbb"), std::invalid_argument);
}
}

File diff suppressed because it is too large Load Diff