---
-Checks: 'google-readability-casting,modernize-use-default-member-init,modernize-use-using,readability-redundant-member-init'
+Checks: 'google-readability-casting,modernize-deprecated-headers,modernize-loop-convert,modernize-use-auto,modernize-use-default-member-init,modernize-use-using,readability-else-after-return,readability-redundant-member-init,readability-redundant-string-cstr'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
# CMake-generated files:
CMakeFiles/
-*.cmake
/pkg-config/jsoncpp.pc
jsoncpp_lib_static.dir/
echo ${CXX}
${CXX} --version
_COMPILER_NAME=`basename ${CXX}`
-if [ "${BUILD_TYPE}" == "shared" ]; then
+if [ "${LIB_TYPE}" = "shared" ]; then
_CMAKE_BUILD_SHARED_LIBS=ON
else
_CMAKE_BUILD_SHARED_LIBS=OFF
Brandon Myers <bmyers1788@gmail.com>
Brendan Drew <brendan.drew@daqri.com>
chason <cxchao802@gmail.com>
+chenguoping <chenguopingdota@163.com>
Chris Gilling <cgilling@iparadigms.com>
Christopher Dawes <christopher.dawes.1981@googlemail.com>
Christopher Dunn <cdunn2001@gmail.com>
Sergiy80 <sil2004@gmail.com>
sergzub <sergzub@gmail.com>
Stefan Schweter <stefan@schweter.it>
+Stefano Fiorentino <stefano.fiore84@gmail.com>
Steffen Kieß <Steffen.Kiess@ipvs.uni-stuttgart.de>
Steven Hahn <hahnse@ornl.gov>
Stuart Eichert <stuart@fivemicro.com>
endif()
endforeach()
-# ==== Define language standard configurations requiring at least c++11 standard
-if(CMAKE_CXX_STANDARD EQUAL "98" )
- message(FATAL_ERROR "CMAKE_CXX_STANDARD:STRING=98 is not supported.")
-endif()
-
-#####
-## Set the default target properties
-if(NOT CMAKE_CXX_STANDARD)
- set(CMAKE_CXX_STANDARD 11) # Supported values are ``11``, ``14``, and ``17``.
-endif()
-if(NOT CMAKE_CXX_STANDARD_REQUIRED)
- set(CMAKE_CXX_STANDARD_REQUIRED ON)
-endif()
-if(NOT CMAKE_CXX_EXTENSIONS)
- set(CMAKE_CXX_EXTENSIONS OFF)
+# Build the library with C++11 standard support, independent from other including
+# software which may use a different CXX_STANDARD or CMAKE_CXX_STANDARD.
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Ensure that CMAKE_BUILD_TYPE has a value specified for single configuration generators.
+if(NOT DEFINED CMAKE_BUILD_TYPE AND NOT DEFINED CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING
+ "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.")
endif()
-# ====
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
-# Ensures that CMAKE_BUILD_TYPE has a default value
-if(NOT DEFINED CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Release CACHE STRING
- "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.")
+# ---------------------------------------------------------------------------
+# use ccache if found, has to be done before project()
+# ---------------------------------------------------------------------------
+find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin)
+if(CCACHE_EXECUTABLE)
+ message(STATUS "use ccache")
+ set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE)
+ set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE)
endif()
-project(JSONCPP
+project(jsoncpp
# Note: version must be updated in three places when doing a release. This
# annoying process ensures that amalgamate, CMake, and meson all report the
# correct version.
- # 1. /meson.build
- # 2. /include/json/version.h
- # 3. /CMakeLists.txt
- # IMPORTANT: also update the SOVERSION!!
- VERSION 1.9.2 # <major>[.<minor>[.<patch>[.<tweak>]]]
+ # 1. ./meson.build
+ # 2. ./include/json/version.h
+ # 3. ./CMakeLists.txt
+ # IMPORTANT: also update the PROJECT_SOVERSION!!
+ VERSION 1.9.4 # <major>[.<minor>[.<patch>[.<tweak>]]]
LANGUAGES CXX)
-message(STATUS "JsonCpp Version: ${JSONCPP_VERSION_MAJOR}.${JSONCPP_VERSION_MINOR}.${JSONCPP_VERSION_PATCH}")
-set( JSONCPP_SOVERSION 22 )
+message(STATUS "JsonCpp Version: ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+set(PROJECT_SOVERSION 24)
option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" ON)
option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" ON)
option(JSONCPP_WITH_STRICT_ISO "Issue all the warnings demanded by strict ISO C and ISO C++" ON)
option(JSONCPP_WITH_PKGCONFIG_SUPPORT "Generate and install .pc files" ON)
option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" ON)
-option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF)
-
-# Enable runtime search path support for dynamic libraries on OSX
-if(APPLE)
- set(CMAKE_MACOSX_RPATH 1)
-endif()
+option(JSONCPP_WITH_EXAMPLE "Compile JsonCpp example" OFF)
+option(BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." ON)
+option(BUILD_STATIC_LIBS "Build jsoncpp_lib as a static library." ON)
+option(BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." ON)
# Adhere to GNU filesystem layout conventions
include(GNUInstallDirs)
-set(DEBUG_LIBNAME_SUFFIX "" CACHE STRING "Optional suffix to append to the library name for a debug build")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Archive output dir.")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE PATH "Library output dir.")
+set(CMAKE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "PDB (MSVC debug symbol)output dir.")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Executable/dll output dir.")
-set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL" )
+set(JSONCPP_USE_SECURE_MEMORY "0" CACHE STRING "-D...=1 to use memory-wiping allocator for STL")
-configure_file( "${PROJECT_SOURCE_DIR}/version.in"
- "${PROJECT_BINARY_DIR}/version"
- NEWLINE_STYLE UNIX )
+configure_file("${PROJECT_SOURCE_DIR}/version.in"
+ "${PROJECT_BINARY_DIR}/version"
+ NEWLINE_STYLE UNIX)
-macro(UseCompilationWarningAsError)
+macro(use_compilation_warning_as_error)
if(MSVC)
# Only enabled in debug because some old versions of VS STL generate
# warnings when compiled in release configuration.
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options($<$<CONFIG:Debug>:/WX>)
- else()
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /WX ")
- endif()
+ add_compile_options($<$<CONFIG:Debug>:/WX>)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options(-Werror)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
- endif()
+ add_compile_options(-Werror)
if(JSONCPP_WITH_STRICT_ISO)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
add_compile_options(-pedantic-errors)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic-errors")
- endif()
endif()
endif()
endmacro()
# Include our configuration header
-include_directories( ${jsoncpp_SOURCE_DIR}/include )
+include_directories(${jsoncpp_SOURCE_DIR}/include)
if(MSVC)
# Only enabled in debug because some old versions of VS STL generate
# unreachable code warning when compiled in release configuration.
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options($<$<CONFIG:Debug>:/W4>)
- else()
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 ")
- endif()
+ add_compile_options($<$<CONFIG:Debug>:/W4>)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# using regular Clang or AppleClang
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare")
- endif()
+ add_compile_options(-Wall -Wconversion -Wshadow -Werror=conversion -Werror=sign-compare)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options(-Wall -Wconversion -Wshadow -Wextra)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra")
- endif()
+ add_compile_options(-Wall -Wconversion -Wshadow -Wextra)
# not yet ready for -Wsign-conversion
if(JSONCPP_WITH_STRICT_ISO)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options(-pedantic)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
- endif()
+ add_compile_options(-Wpedantic)
endif()
if(JSONCPP_WITH_WARNING_AS_ERROR)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
add_compile_options(-Werror=conversion)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=conversion")
- endif()
endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
# using Intel compiler
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wconversion -Wshadow -Wextra -Werror=conversion")
- endif()
+ add_compile_options(-Wall -Wconversion -Wshadow -Wextra -Werror=conversion)
if(JSONCPP_WITH_STRICT_ISO AND NOT JSONCPP_WITH_WARNING_AS_ERROR)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_options(-pedantic)
- else()
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
- endif()
+ add_compile_options(-Wpedantic)
endif()
endif()
-find_program(CCACHE_FOUND ccache)
-if(CCACHE_FOUND)
- set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
- set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
-endif(CCACHE_FOUND)
-
if(JSONCPP_WITH_WARNING_AS_ERROR)
- UseCompilationWarningAsError()
+ use_compilation_warning_as_error()
endif()
if(JSONCPP_WITH_PKGCONFIG_SUPPORT)
+ include(JoinPaths)
+
+ join_paths(libdir_for_pc_file "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}")
+ join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
+
configure_file(
"pkg-config/jsoncpp.pc.in"
"pkg-config/jsoncpp.pc"
endif()
if(JSONCPP_WITH_CMAKE_PACKAGE)
- include (CMakePackageConfigHelpers)
- install(EXPORT jsoncpp
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp
- FILE jsoncppConfig.cmake)
- write_basic_package_version_file ("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake"
- VERSION ${PROJECT_VERSION}
- COMPATIBILITY SameMajorVersion)
- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake
- DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)
+ include(CMakePackageConfigHelpers)
+ install(EXPORT jsoncpp
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp
+ FILE jsoncppConfig.cmake)
+ write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY SameMajorVersion)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jsoncppConfigVersion.cmake
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/jsoncpp)
endif()
if(JSONCPP_WITH_TESTS)
- enable_testing()
- include(CTest)
+ enable_testing()
+ include(CTest)
endif()
# Build the different applications
-add_subdirectory( src )
+add_subdirectory(src)
#install the includes
-add_subdirectory( include )
+add_subdirectory(include)
#install the example
-add_subdirectory( example )
+if(JSONCPP_WITH_EXAMPLE)
+ add_subdirectory(example)
+endif()
#LIB_TYPE=static
meson --buildtype ${BUILD_TYPE} --default-library ${LIB_TYPE} . build-${LIB_TYPE}
ninja -v -C build-${LIB_TYPE}
- cd build-${LIB_TYPE}
- meson test --no-rebuild --print-errorlogs
+
+ ninja -C build-static/ test
+
+ # Or
+ #cd build-${LIB_TYPE}
+ #meson test --no-rebuild --print-errorlogs
+
sudo ninja install
## Building and testing with other build systems
* `1.y.z` is built with C++11.
* `0.y.z` can be used with older compilers.
+* `00.11.z` can be used both in old and new compilers.
* Major versions maintain binary-compatibility.
+### Special note
+The branch `00.11.z`is a new branch, its major version number `00` is to show that it is
+different from `0.y.z` and `1.y.z`, the main purpose of this branch is to make a balance
+between the other two branches. Thus, users can use some new features in this new branch
+that introduced in 1.y.z, but can hardly applied into 0.y.z.
## Using JsonCpp in your project
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
- vcpkg install jsoncpp
+ ./vcpkg install jsoncpp
The JsonCpp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
header.add_text("/// If defined, indicates that the source file is amalgamated")
header.add_text("/// to prevent private header inclusion.")
header.add_text("#define JSON_IS_AMALGAMATION")
+ header.add_file(os.path.join(INCLUDE_PATH, "version.h"))
+ header.add_file(os.path.join(INCLUDE_PATH, "allocator.h"))
header.add_file(os.path.join(INCLUDE_PATH, "config.h"))
header.add_file(os.path.join(INCLUDE_PATH, "forwards.h"))
header.add_text("#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED")
--- /dev/null
+# This module provides a function for joining paths
+# known from most languages
+#
+# SPDX-License-Identifier: (MIT OR CC0-1.0)
+# Copyright 2020 Jan Tojnar
+# https://github.com/jtojnar/cmake-snips
+#
+# Modelled after Python’s os.path.join
+# https://docs.python.org/3.7/library/os.path.html#os.path.join
+# Windows not supported
+function(join_paths joined_path first_path_segment)
+ set(temp_path "${first_path_segment}")
+ foreach(current_segment IN LISTS ARGN)
+ if(NOT ("${current_segment}" STREQUAL ""))
+ if(IS_ABSOLUTE "${current_segment}")
+ set(temp_path "${current_segment}")
+ else()
+ set(temp_path "${temp_path}/${current_segment}")
+ endif()
+ endif()
+ endforeach()
+ set(${joined_path} "${temp_path}" PARENT_SCOPE)
+endfunction()
#vim: et ts =4 sts = 4 sw = 4 tw = 0
-cmake_minimum_required(VERSION 3.1)
-
set(EXAMPLES
- readFromString
- readFromStream
- stringWrite
- streamWrite
- )
+ readFromString
+ readFromStream
+ stringWrite
+ streamWrite
+)
add_definitions(-D_GLIBCXX_USE_CXX11_ABI)
-set_property(DIRECTORY PROPERTY COMPILE_OPTIONS ${EXTRA_CXX_FLAGS})
-if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra ")
-else()
- add_definitions(
- -D_SCL_SECURE_NO_WARNINGS
- -D_CRT_SECURE_NO_WARNINGS
- -D_WIN32_WINNT=0x601
- -D_WINSOCK_DEPRECATED_NO_WARNINGS)
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ add_compile_options(-Wall -Wextra)
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
+ add_definitions(
+ -D_SCL_SECURE_NO_WARNINGS
+ -D_CRT_SECURE_NO_WARNINGS
+ -D_WIN32_WINNT=0x601
+ -D_WINSOCK_DEPRECATED_NO_WARNINGS
+ )
endif()
-foreach (example ${EXAMPLES})
- add_executable(${example} ${example}/${example}.cpp)
- target_include_directories(${example} PUBLIC ${CMAKE_SOURCE_DIR}/include)
- target_link_libraries(${example} jsoncpp_lib)
+foreach(example ${EXAMPLES})
+ add_executable(${example} ${example}/${example}.cpp)
+ target_include_directories(${example} PUBLIC ${CMAKE_SOURCE_DIR}/include)
+ target_link_libraries(${example} jsoncpp_lib)
endforeach()
add_custom_target(examples ALL DEPENDS ${EXAMPLES})
*/
int main() {
const std::string rawJson = R"({"Age": 20, "Name": "colin"})";
- const int rawJsonLength = static_cast<int>(rawJson.length());
+ const auto rawJsonLength = static_cast<int>(rawJson.length());
constexpr bool shouldUseOldWay = false;
JSONCPP_STRING err;
Json::Value root;
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED
-#define CPPTL_JSON_ALLOCATOR_H_INCLUDED
+#ifndef JSON_ALLOCATOR_H_INCLUDED
+#define JSON_ALLOCATOR_H_INCLUDED
#include <cstring>
#include <memory>
#pragma pack(pop)
-#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED
+#endif // JSON_ALLOCATOR_H_INCLUDED
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
-#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#ifndef JSON_ASSERTIONS_H_INCLUDED
+#define JSON_ASSERTIONS_H_INCLUDED
#include <cstdlib>
#include <sstream>
// @todo <= add detail about condition in exception
#define JSON_ASSERT(condition) \
- { \
+ do { \
if (!(condition)) { \
Json::throwLogicError("assert json failed"); \
} \
- }
+ } while (0)
#define JSON_FAIL_MESSAGE(message) \
- { \
+ do { \
OStringStream oss; \
oss << message; \
Json::throwLogicError(oss.str()); \
abort(); \
- }
+ } while (0)
#else // JSON_USE_EXCEPTION
#endif
#define JSON_ASSERT_MESSAGE(condition, message) \
- if (!(condition)) { \
- JSON_FAIL_MESSAGE(message); \
- }
+ do { \
+ if (!(condition)) { \
+ JSON_FAIL_MESSAGE(message); \
+ } \
+ } while (0)
-#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#endif // JSON_ASSERTIONS_H_INCLUDED
+++ /dev/null
-// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
-// Distributed under MIT license, or public domain if desired and
-// recognized in your jurisdiction.
-// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-
-#ifndef JSON_AUTOLINK_H_INCLUDED
-#define JSON_AUTOLINK_H_INCLUDED
-
-#include "config.h"
-
-#ifdef JSON_IN_CPPTL
-#include <cpptl/cpptl_autolink.h>
-#endif
-
-#if !defined(JSON_NO_AUTOLINK) && !defined(JSON_DLL_BUILD) && \
- !defined(JSON_IN_CPPTL)
-#define CPPTL_AUTOLINK_NAME "json"
-#undef CPPTL_AUTOLINK_DLL
-#ifdef JSON_DLL
-#define CPPTL_AUTOLINK_DLL
-#endif
-#include "autolink.h"
-#endif
-
-#endif // JSON_AUTOLINK_H_INCLUDED
#include <string>
#include <type_traits>
-/// If defined, indicates that json library is embedded in CppTL library.
-//# define JSON_IN_CPPTL 1
-
-/// If defined, indicates that json may leverage CppTL library
-//# define JSON_USE_CPPTL 1
-/// If defined, indicates that cpptl vector based map should be used instead of
-/// std::map
-/// as Value container.
-//# define JSON_USE_CPPTL_SMALLMAP 1
-
// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
/// Remarks: it is automatically defined in the generated amalgamated header.
// #define JSON_IS_AMALGAMATION
-#ifdef JSON_IN_CPPTL
-#include <cpptl/config.h>
-#ifndef JSON_USE_CPPTL
-#define JSON_USE_CPPTL 1
-#endif
-#endif
-
-#ifdef JSON_IN_CPPTL
-#define JSON_API CPPTL_API
-#elif defined(JSON_DLL_BUILD)
+// Export macros for DLL visibility
+#if defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#elif defined(__GNUC__) || defined(__clang__)
#define JSON_API __attribute__((visibility("default")))
#endif // if defined(_MSC_VER)
+
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
-#endif // ifdef JSON_IN_CPPTL
+#endif // ifdef JSON_DLL_BUILD
+
#if !defined(JSON_API)
#define JSON_API
#endif
// C++11 should be used directly in JSONCPP.
#define JSONCPP_OVERRIDE override
-#if __cplusplus >= 201103L
-#define JSONCPP_NOEXCEPT noexcept
-#define JSONCPP_OP_EXPLICIT explicit
-#elif defined(_MSC_VER) && _MSC_VER < 1900
-#define JSONCPP_NOEXCEPT throw()
-#define JSONCPP_OP_EXPLICIT explicit
-#elif defined(_MSC_VER) && _MSC_VER >= 1900
-#define JSONCPP_NOEXCEPT noexcept
-#define JSONCPP_OP_EXPLICIT explicit
-#else
-#define JSONCPP_NOEXCEPT throw()
-#define JSONCPP_OP_EXPLICIT
-#endif
-
#ifdef __clang__
#if __has_extension(attribute_deprecated_with_message)
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
-typedef int Int;
-typedef unsigned int UInt;
+using Int = int;
+using UInt = unsigned int;
#if defined(JSON_NO_INT64)
-typedef int LargestInt;
-typedef unsigned int LargestUInt;
+using LargestInt = int;
+using LargestUInt = unsigned int;
#undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio
-typedef __int64 Int64;
-typedef unsigned __int64 UInt64;
+using Int64 = __int64;
+using UInt64 = unsigned __int64;
#else // if defined(_MSC_VER) // Other platforms, use long long
-typedef int64_t Int64;
-typedef uint64_t UInt64;
+using Int64 = int64_t;
+using UInt64 = uint64_t;
#endif // if defined(_MSC_VER)
-typedef Int64 LargestInt;
-typedef UInt64 LargestUInt;
+using LargestInt = Int64;
+using LargestUInt = UInt64;
#define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64)
class Features;
// value.h
-typedef unsigned int ArrayIndex;
+using ArrayIndex = unsigned int;
class StaticString;
class Path;
class PathArgument;
#ifndef JSON_JSON_H_INCLUDED
#define JSON_JSON_H_INCLUDED
-#include "autolink.h"
+#include "config.h"
#include "json_features.h"
#include "reader.h"
#include "value.h"
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
-#define CPPTL_JSON_FEATURES_H_INCLUDED
+#ifndef JSON_FEATURES_H_INCLUDED
+#define JSON_FEATURES_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#pragma pack(pop)
-#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+#endif // JSON_FEATURES_H_INCLUDED
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-#ifndef CPPTL_JSON_READER_H_INCLUDED
-#define CPPTL_JSON_READER_H_INCLUDED
+#ifndef JSON_READER_H_INCLUDED
+#define JSON_READER_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "json_features.h"
class JSONCPP_DEPRECATED(
"Use CharReader and CharReaderBuilder instead.") JSON_API Reader {
public:
- typedef char Char;
- typedef const Char* Location;
+ using Char = char;
+ using Location = const Char*;
/** \brief An error tagged with where in the JSON text it was encountered.
*
Location extra_;
};
- typedef std::deque<ErrorInfo> Errors;
+ using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token);
void skipSpaces();
static bool containsNewLine(Location begin, Location end);
static String normalizeEOL(Location begin, Location end);
- typedef std::stack<Value*> Nodes;
+ using Nodes = std::stack<Value*>;
Nodes nodes_;
Errors errors_;
String document_;
* if allowComments is false.
* - `"allowComments": false or true`
* - true if comments are allowed.
+ * - `"allowTrailingCommas": false or true`
+ * - true if trailing commas in objects and arrays are allowed.
* - `"strictRoot": false or true`
* - true if root must be either an array or an object value
* - `"allowDroppedNullPlaceholders": false or true`
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
-#endif // CPPTL_JSON_READER_H_INCLUDED
+#endif // JSON_READER_H_INCLUDED
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
-#ifndef CPPTL_JSON_H_INCLUDED
-#define CPPTL_JSON_H_INCLUDED
+#ifndef JSON_H_INCLUDED
+#define JSON_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif
#endif
+// Support for '= delete' with template declarations was a late addition
+// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
+// even though these declare themselves to be c++11 compilers.
+#if !defined(JSONCPP_TEMPLATE_DELETE)
+#if defined(__clang__) && defined(__apple_build_version__)
+#if __apple_build_version__ <= 8000042
+#define JSONCPP_TEMPLATE_DELETE
+#endif
+#elif defined(__clang__)
+#if __clang_major__ == 3 && __clang_minor__ <= 8
+#define JSONCPP_TEMPLATE_DELETE
+#endif
+#endif
+#if !defined(JSONCPP_TEMPLATE_DELETE)
+#define JSONCPP_TEMPLATE_DELETE = delete
+#endif
+#endif
+
#include <array>
#include <exception>
+#include <map>
#include <memory>
#include <string>
#include <vector>
-#ifndef JSON_USE_CPPTL_SMALLMAP
-#include <map>
-#else
-#include <cpptl/smallmap.h>
-#endif
-#ifdef JSON_USE_CPPTL
-#include <cpptl/forwards.h>
-#endif
-
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
class JSON_API Exception : public std::exception {
public:
Exception(String msg);
- ~Exception() JSONCPP_NOEXCEPT override;
- char const* what() const JSONCPP_NOEXCEPT override;
+ ~Exception() noexcept override;
+ char const* what() const noexcept override;
protected:
String msg_;
decimalPlaces ///< we set max number of digits after "." in string
};
-//# ifdef JSON_USE_CPPTL
-// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
-// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
-//# endif
-
/** \brief Lightweight wrapper to tag static string.
*
* Value constructor and objectValue member assignment takes advantage of the
friend class ValueIteratorBase;
public:
- typedef std::vector<String> Members;
- typedef ValueIterator iterator;
- typedef ValueConstIterator const_iterator;
- typedef Json::UInt UInt;
- typedef Json::Int Int;
+ using Members = std::vector<String>;
+ using iterator = ValueIterator;
+ using const_iterator = ValueConstIterator;
+ using UInt = Json::UInt;
+ using Int = Json::Int;
#if defined(JSON_HAS_INT64)
- typedef Json::UInt64 UInt64;
- typedef Json::Int64 Int64;
+ using UInt64 = Json::UInt64;
+ using Int64 = Json::Int64;
#endif // defined(JSON_HAS_INT64)
- typedef Json::LargestInt LargestInt;
- typedef Json::LargestUInt LargestUInt;
- typedef Json::ArrayIndex ArrayIndex;
+ using LargestInt = Json::LargestInt;
+ using LargestUInt = Json::LargestUInt;
+ using ArrayIndex = Json::ArrayIndex;
// Required for boost integration, e. g. BOOST_TEST
- typedef std::string value_type;
+ using value_type = std::string;
#if JSON_USE_NULLREF
// Binary compatibility kludges, do not use.
};
public:
-#ifndef JSON_USE_CPPTL_SMALLMAP
typedef std::map<CZString, Value> ObjectValues;
-#else
- typedef CppTL::SmallMap<CZString, Value> ObjectValues;
-#endif // ifndef JSON_USE_CPPTL_SMALLMAP
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
public:
*/
Value(const StaticString& value);
Value(const String& value);
-#ifdef JSON_USE_CPPTL
- Value(const CppTL::ConstString& value);
-#endif
Value(bool value);
+ Value(std::nullptr_t ptr) = delete;
Value(const Value& other);
Value(Value&& other);
~Value();
* \return false if !string. (Seg-fault if str or end are NULL.)
*/
bool getString(char const** begin, char const** end) const;
-#ifdef JSON_USE_CPPTL
- CppTL::ConstString asConstString() const;
-#endif
Int asInt() const;
UInt asUInt() const;
#if defined(JSON_HAS_INT64)
bool isObject() const;
/// The `as<T>` and `is<T>` member function templates and specializations.
- template <typename T> T as() const = delete;
- template <typename T> bool is() const = delete;
+ template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
+ template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;
bool isConvertibleTo(ValueType other) const;
bool empty() const;
/// Return !isNull()
- JSONCPP_OP_EXPLICIT operator bool() const;
+ explicit operator bool() const;
/// Remove all object members and array elements.
/// \pre type() is arrayValue, objectValue, or nullValue
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value);
Value& append(Value&& value);
+
/// \brief Insert value in array at specific index
- bool insert(ArrayIndex index, Value newValue);
+ bool insert(ArrayIndex index, const Value& newValue);
+ bool insert(ArrayIndex index, Value&& newValue);
/// Access an object value by name, create a null member if it does not exist.
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
* \endcode
*/
Value& operator[](const StaticString& key);
-#ifdef JSON_USE_CPPTL
- /// Access an object value by name, create a null member if it does not exist.
- Value& operator[](const CppTL::ConstString& key);
- /// Access an object value by name, returns null if there is no member with
- /// that name.
- const Value& operator[](const CppTL::ConstString& key) const;
-#endif
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(const char* key, const Value& defaultValue) const;
/// \note deep copy
/// \param key may contain embedded nulls.
Value get(const String& key, const Value& defaultValue) const;
-#ifdef JSON_USE_CPPTL
- /// Return the member named key if it exist, defaultValue otherwise.
- /// \note deep copy
- Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
-#endif
/// Most general and efficient version of isMember()const, get()const,
/// and operator[]const
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
bool isMember(const String& key) const;
/// Same as isMember(String const& key)const
bool isMember(const char* begin, const char* end) const;
-#ifdef JSON_USE_CPPTL
- /// Return true if the object has a member named key.
- bool isMember(const CppTL::ConstString& key) const;
-#endif
/// \brief Return a list of the member names.
///
/// \post if type() was nullValue, it remains nullValue
Members getMemberNames() const;
- //# ifdef JSON_USE_CPPTL
- // EnumMemberNames enumMemberNames() const;
- // EnumValues enumValues() const;
- //# endif
-
/// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
void setComment(const char* comment, CommentPlacement placement) {
template <> inline const char* Value::as<const char*>() const {
return asCString();
}
-#ifdef JSON_USE_CPPTL
-template <> inline CppTL::ConstString Value::as<CppTL::ConstString>() const {
- return asConstString();
-}
-#endif
/** \brief Experimental and untested: represents an element of the "path" to
* access a node.
Value& make(Value& root) const;
private:
- typedef std::vector<const PathArgument*> InArgs;
- typedef std::vector<PathArgument> Args;
+ using InArgs = std::vector<const PathArgument*>;
+ using Args = std::vector<PathArgument>;
void makePath(const String& path, const InArgs& in);
void addPathInArg(const String& path, const InArgs& in,
*/
class JSON_API ValueIteratorBase {
public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef unsigned int size_t;
- typedef int difference_type;
- typedef ValueIteratorBase SelfType;
+ using iterator_category = std::bidirectional_iterator_tag;
+ using size_t = unsigned int;
+ using difference_type = int;
+ using SelfType = ValueIteratorBase;
bool operator==(const SelfType& other) const { return isEqual(other); }
friend class Value;
public:
- typedef const Value value_type;
+ using value_type = const Value;
// typedef unsigned int size_t;
// typedef int difference_type;
- typedef const Value& reference;
- typedef const Value* pointer;
- typedef ValueConstIterator SelfType;
+ using reference = const Value&;
+ using pointer = const Value*;
+ using SelfType = ValueConstIterator;
ValueConstIterator();
ValueConstIterator(ValueIterator const& other);
friend class Value;
public:
- typedef Value value_type;
- typedef unsigned int size_t;
- typedef int difference_type;
- typedef Value& reference;
- typedef Value* pointer;
- typedef ValueIterator SelfType;
+ using value_type = Value;
+ using size_t = unsigned int;
+ using difference_type = int;
+ using reference = Value&;
+ using pointer = Value*;
+ using SelfType = ValueIterator;
ValueIterator();
explicit ValueIterator(const ValueConstIterator& other);
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
-#endif // CPPTL_JSON_H_INCLUDED
+#endif // JSON_H_INCLUDED
// 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!!
-#define JSONCPP_VERSION_STRING "1.9.2"
+#define JSONCPP_VERSION_STRING "1.9.4"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9
-#define JSONCPP_VERSION_PATCH 2
+#define JSONCPP_VERSION_PATCH 3
#define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text);
- typedef std::vector<String> ChildValues;
+ using ChildValues = std::vector<String>;
ChildValues childValues_;
String document_;
static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text);
- typedef std::vector<String> ChildValues;
+ using ChildValues = std::vector<String>;
ChildValues childValues_;
OStream* document_;
# 2. /include/json/version.h
# 3. /CMakeLists.txt
# IMPORTANT: also update the SOVERSION!!
- version : '1.9.2',
+ version : '1.9.4',
default_options : [
'buildtype=release',
'cpp_std=c++11',
meson_version : '>= 0.49.0')
-jsoncpp_headers = [
+jsoncpp_headers = files([
'include/json/allocator.h',
'include/json/assertions.h',
- 'include/json/autolink.h',
'include/json/config.h',
'include/json/json_features.h',
'include/json/forwards.h',
'include/json/reader.h',
'include/json/value.h',
'include/json/version.h',
- 'include/json/writer.h']
+ 'include/json/writer.h',
+])
jsoncpp_include_directories = include_directories('include')
install_headers(
endif
jsoncpp_lib = library(
- 'jsoncpp',
- [ jsoncpp_headers,
- 'src/lib_json/json_tool.h',
+ 'jsoncpp', files([
'src/lib_json/json_reader.cpp',
'src/lib_json/json_value.cpp',
- 'src/lib_json/json_writer.cpp'],
- soversion : 22,
+ 'src/lib_json/json_writer.cpp',
+ ]),
+ soversion : 24,
install : true,
include_directories : jsoncpp_include_directories,
cpp_args: dll_export_flag)
jsoncpp_dep = declare_dependency(
include_directories : jsoncpp_include_directories,
link_with : jsoncpp_lib,
- version : meson.project_version(),
- )
+ version : meson.project_version())
# tests
+if meson.is_subproject() or not get_option('tests')
+ subdir_done()
+endif
+
python = import('python').find_installation()
jsoncpp_test = executable(
- 'jsoncpp_test',
- [ 'src/test_lib_json/jsontest.cpp',
- 'src/test_lib_json/jsontest.h',
+ 'jsoncpp_test', files([
+ 'src/test_lib_json/jsontest.cpp',
'src/test_lib_json/main.cpp',
- 'src/test_lib_json/fuzz.cpp'],
+ 'src/test_lib_json/fuzz.cpp',
+ ]),
include_directories : jsoncpp_include_directories,
link_with : jsoncpp_lib,
install : false,
'-B',
join_paths(meson.current_source_dir(), 'test/runjsontests.py'),
jsontestrunner,
- join_paths(meson.current_source_dir(), 'test/data')]
+ join_paths(meson.current_source_dir(), 'test/data')],
+ )
+test(
+ 'jsonchecker_jsontestrunner',
+ python,
+ is_parallel : false,
+ args : [
+ '-B',
+ join_paths(meson.current_source_dir(), 'test/runjsontests.py'),
+ '--with-json-checker',
+ jsontestrunner,
+ join_paths(meson.current_source_dir(), 'test/data')],
+ workdir : join_paths(meson.current_source_dir(), 'test/data'),
)
--- /dev/null
+option(
+ 'tests',
+ type : 'boolean',
+ value : true,
+ description : 'Enable building tests')
prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
-libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
-includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
+libdir=@libdir_for_pc_file@
+includedir=@includedir_for_pc_file@
Name: jsoncpp
Description: A C++ library for interacting with JSON
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- # The new Python3 module is much more robust than the previous PythonInterp
- find_package (Python3 COMPONENTS Interpreter)
- # Set variables for backwards compatibility with cmake < 3.12.0
- set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND})
- set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
+ # The new Python3 module is much more robust than the previous PythonInterp
+ find_package(Python3 COMPONENTS Interpreter)
+ # Set variables for backwards compatibility with cmake < 3.12.0
+ set(PYTHONINTERP_FOUND ${Python3_Interpreter_FOUND})
+ set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE})
else()
- set(Python_ADDITIONAL_VERSIONS 3.8)
- find_package(PythonInterp 3)
+ set(Python_ADDITIONAL_VERSIONS 3.8)
+ find_package(PythonInterp 3)
endif()
add_executable(jsontestrunner_exe
- main.cpp
- )
+ main.cpp
+)
if(BUILD_SHARED_LIBS)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_definitions( JSON_DLL )
- else()
- add_definitions( -DJSON_DLL )
- endif()
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
+ add_compile_definitions( JSON_DLL )
+ else()
+ add_definitions(-DJSON_DLL)
+ endif()
+ target_link_libraries(jsontestrunner_exe jsoncpp_lib)
+else()
+ target_link_libraries(jsontestrunner_exe jsoncpp_static)
endif()
-target_link_libraries(jsontestrunner_exe jsoncpp_lib)
set_target_properties(jsontestrunner_exe PROPERTIES OUTPUT_NAME jsontestrunner_exe)
# Run unit tests in post-build
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
add_custom_target(jsoncpp_readerwriter_tests
- "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
- DEPENDS jsontestrunner_exe jsoncpp_test
- )
+ "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
+ DEPENDS jsontestrunner_exe jsoncpp_test
+ )
add_custom_target(jsoncpp_check DEPENDS jsoncpp_readerwriter_tests)
## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp
add_test(NAME jsoncpp_readerwriter
- COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
- WORKING_DIRECTORY "${TEST_DIR}/data"
+ COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
+ WORKING_DIRECTORY "${TEST_DIR}/data"
)
add_test(NAME jsoncpp_readerwriter_json_checker
- COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
- WORKING_DIRECTORY "${TEST_DIR}/data"
+ COMMAND "${PYTHON_EXECUTABLE}" -B "${RUNJSONTESTS_PATH}" --with-json-checker $<TARGET_FILE:jsontestrunner_exe> "${TEST_DIR}/data"
+ WORKING_DIRECTORY "${TEST_DIR}/data"
)
endif()
if (!file)
return "";
fseek(file, 0, SEEK_END);
- long const size = ftell(file);
- size_t const usize = static_cast<unsigned long>(size);
+ auto const size = ftell(file);
+ auto const usize = static_cast<size_t>(size);
fseek(file, 0, SEEK_SET);
- char* buffer = new char[size + 1];
+ auto buffer = new char[size + 1];
buffer[size] = 0;
Json::String text;
if (fread(buffer, 1, usize, file) == usize)
Json::Value::Members members(value.getMemberNames());
std::sort(members.begin(), members.end());
Json::String suffix = *(path.end() - 1) == '.' ? "" : ".";
- for (auto name : members) {
+ for (const auto& name : members) {
printValueTree(fout, value[name], path + suffix + name);
}
} break;
-if( CMAKE_COMPILER_IS_GNUCXX )
- #Get compiler version.
- execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
- OUTPUT_VARIABLE GNUCXX_VERSION )
-
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.1.2)
#-Werror=* was introduced -after- GCC 4.1.2
- if( GNUCXX_VERSION VERSION_GREATER 4.1.2 )
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=strict-aliasing")
- endif()
-endif( CMAKE_COMPILER_IS_GNUCXX )
+ add_compile_options("-Werror=strict-aliasing")
+endif()
include(CheckIncludeFileCXX)
include(CheckTypeSize)
if(NOT (HAVE_CLOCALE AND HAVE_LCONV_SIZE AND HAVE_DECIMAL_POINT AND HAVE_LOCALECONV))
message(WARNING "Locale functionality is not supported")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_definitions(JSONCPP_NO_LOCALE_SUPPORT)
+ add_compile_definitions(JSONCPP_NO_LOCALE_SUPPORT)
else()
- add_definitions(-DJSONCPP_NO_LOCALE_SUPPORT)
+ add_definitions(-DJSONCPP_NO_LOCALE_SUPPORT)
endif()
endif()
-set( JSONCPP_INCLUDE_DIR ../../include )
+set(JSONCPP_INCLUDE_DIR ../../include)
-set( PUBLIC_HEADERS
+set(PUBLIC_HEADERS
${JSONCPP_INCLUDE_DIR}/json/config.h
${JSONCPP_INCLUDE_DIR}/json/forwards.h
${JSONCPP_INCLUDE_DIR}/json/json_features.h
${JSONCPP_INCLUDE_DIR}/json/version.h
${JSONCPP_INCLUDE_DIR}/json/writer.h
${JSONCPP_INCLUDE_DIR}/json/assertions.h
- )
+)
-source_group( "Public API" FILES ${PUBLIC_HEADERS} )
+source_group("Public API" FILES ${PUBLIC_HEADERS})
-set(jsoncpp_sources
- json_tool.h
- json_reader.cpp
- json_valueiterator.inl
- json_value.cpp
- json_writer.cpp)
+set(JSONCPP_SOURCES
+ json_tool.h
+ json_reader.cpp
+ json_valueiterator.inl
+ json_value.cpp
+ json_writer.cpp
+)
# Install instructions for this target
if(JSONCPP_WITH_CMAKE_PACKAGE)
set(INSTALL_EXPORT EXPORT jsoncpp)
-else(JSONCPP_WITH_CMAKE_PACKAGE)
+else()
set(INSTALL_EXPORT)
endif()
-
-if(BUILD_SHARED_LIBS)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_definitions( JSON_DLL_BUILD )
- else()
- add_definitions( -DJSON_DLL_BUILD )
- endif()
-endif()
-
-
-add_library(jsoncpp_lib ${PUBLIC_HEADERS} ${jsoncpp_sources})
-set_target_properties( jsoncpp_lib PROPERTIES VERSION ${JSONCPP_VERSION} SOVERSION ${JSONCPP_SOVERSION})
-set_target_properties( jsoncpp_lib PROPERTIES OUTPUT_NAME jsoncpp
- DEBUG_OUTPUT_NAME jsoncpp${DEBUG_LIBNAME_SUFFIX} )
-set_target_properties( jsoncpp_lib PROPERTIES POSITION_INDEPENDENT_CODE ON)
-
-# Set library's runtime search path on OSX
-if(APPLE)
- set_target_properties( jsoncpp_lib PROPERTIES INSTALL_RPATH "@loader_path/." )
-endif()
-
# Specify compiler features required when compiling a given target.
# See https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES
# for complete list of features available
-target_compile_features(jsoncpp_lib PUBLIC
+list(APPEND REQUIRED_FEATURES
cxx_std_11 # Compiler mode is aware of C++ 11.
#MSVC 1900 cxx_alignas # Alignment control alignas, as defined in N2341.
#MSVC 1900 cxx_alignof # Alignment control alignof, as defined in N2341.
cxx_variadic_templates # Variadic templates, as defined in N2242.
)
-install( TARGETS jsoncpp_lib ${INSTALL_EXPORT}
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
-if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
- target_include_directories( jsoncpp_lib PUBLIC
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
- $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
- $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>)
+if(BUILD_SHARED_LIBS)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
+ add_compile_definitions(JSON_DLL_BUILD)
+ else()
+ add_definitions(-DJSON_DLL_BUILD)
+ endif()
+
+ set(SHARED_LIB ${PROJECT_NAME}_lib)
+ add_library(${SHARED_LIB} SHARED ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})
+ set_target_properties(${SHARED_LIB} PROPERTIES
+ OUTPUT_NAME jsoncpp
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_SOVERSION}
+ POSITION_INDEPENDENT_CODE ON
+ )
+
+ # Set library's runtime search path on OSX
+ if(APPLE)
+ set_target_properties(${SHARED_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.")
+ endif()
+
+ target_compile_features(${SHARED_LIB} PUBLIC ${REQUIRED_FEATURES})
+
+ if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
+ target_include_directories(${SHARED_LIB} PUBLIC
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
+ )
+ endif()
+
+ list(APPEND CMAKE_TARGETS ${SHARED_LIB})
+endif()
+
+if(BUILD_STATIC_LIBS)
+ set(STATIC_LIB ${PROJECT_NAME}_static)
+ add_library(${STATIC_LIB} STATIC ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})
+
+ # avoid name clashes on windows as the shared import lib is alse named jsoncpp.lib
+ if(NOT DEFINED STATIC_SUFFIX AND BUILD_SHARED_LIBS)
+ set(STATIC_SUFFIX "_static")
+ endif()
+
+ set_target_properties(${STATIC_LIB} PROPERTIES
+ OUTPUT_NAME jsoncpp${STATIC_SUFFIX}
+ VERSION ${PROJECT_VERSION}
+ )
+
+ # Set library's runtime search path on OSX
+ if(APPLE)
+ set_target_properties(${STATIC_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.")
+ endif()
+
+ target_compile_features(${STATIC_LIB} PUBLIC ${REQUIRED_FEATURES})
+
+ if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
+ target_include_directories(${STATIC_LIB} PUBLIC
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
+ )
+ endif()
+
+ list(APPEND CMAKE_TARGETS ${STATIC_LIB})
endif()
+
+if(BUILD_OBJECT_LIBS)
+ set(OBJECT_LIB ${PROJECT_NAME}_object)
+ add_library(${OBJECT_LIB} OBJECT ${PUBLIC_HEADERS} ${JSONCPP_SOURCES})
+
+ set_target_properties(${OBJECT_LIB} PROPERTIES
+ OUTPUT_NAME jsoncpp
+ VERSION ${PROJECT_VERSION}
+ SOVERSION ${PROJECT_SOVERSION}
+ POSITION_INDEPENDENT_CODE ON
+ )
+
+ # Set library's runtime search path on OSX
+ if(APPLE)
+ set_target_properties(${OBJECT_LIB} PROPERTIES INSTALL_RPATH "@loader_path/.")
+ endif()
+
+ target_compile_features(${OBJECT_LIB} PUBLIC ${REQUIRED_FEATURES})
+
+ if(NOT CMAKE_VERSION VERSION_LESS 2.8.11)
+ target_include_directories(${OBJECT_LIB} PUBLIC
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/${JSONCPP_INCLUDE_DIR}>
+ $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include/json>
+ )
+ endif()
+
+ list(APPEND CMAKE_TARGETS ${OBJECT_LIB})
+endif()
+
+install(TARGETS ${CMAKE_TARGETS} ${INSTALL_EXPORT}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
#include <json/reader.h>
#include <json/value.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using CharReaderPtr = std::unique_ptr<CharReader>;
#else
-typedef std::auto_ptr<CharReader> CharReaderPtr;
+using CharReaderPtr = std::auto_ptr<CharReader>;
#endif
// Implementation of class Features
// ////////////////////////////////
bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
- for (; begin < end; ++begin)
- if (*begin == '\n' || *begin == '\r')
- return true;
- return false;
+ return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
}
// Class Reader
Value numberName;
if (!decodeNumber(tokenName, numberName))
return recoverFromError(tokenObjectEnd);
- name = String(numberName.asCString());
+ name = numberName.asString();
} else {
break;
}
Char c = *current++;
if (c == '"')
break;
- else if (c == '\\') {
+ if (c == '\\') {
if (current == end)
return addError("Empty escape sequence in string", token, current);
Char escape = *current++;
public:
static OurFeatures all();
bool allowComments_;
+ bool allowTrailingCommas_;
bool strictRoot_;
bool allowDroppedNullPlaceholders_;
bool allowNumericKeys_;
bool failIfExtra_;
bool rejectDupKeys_;
bool allowSpecialFloats_;
+ bool skipBom_;
size_t stackLimit_;
}; // OurFeatures
bool readToken(Token& token);
void skipSpaces();
+ void skipBom(bool skipBom);
bool match(const Char* pattern, int patternLength);
bool readComment();
bool readCStyleComment(bool* containsNewLineResult);
bool OurReader::containsNewLine(OurReader::Location begin,
OurReader::Location end) {
- for (; begin < end; ++begin)
- if (*begin == '\n' || *begin == '\r')
- return true;
- return false;
+ return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
}
OurReader::OurReader(OurFeatures const& features) : features_(features) {}
nodes_.pop();
nodes_.push(&root);
+ // skip byte order mark if it exists at the beginning of the UTF-8 text.
+ skipBom(features_.skipBom_);
bool successful = readValue();
nodes_.pop();
Token token;
if (features_.allowSingleQuotes_) {
token.type_ = tokenString;
ok = readStringSingleQuote();
- break;
- } // else fall through
+ } else {
+ // If we don't allow single quotes, this is a failure case.
+ ok = false;
+ }
+ break;
case '/':
token.type_ = tokenComment;
ok = readComment();
}
}
+void OurReader::skipBom(bool skipBom) {
+ // The default behavior is to skip BOM.
+ if (skipBom) {
+ if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
+ begin_ += 3;
+ current_ = begin_;
+ }
+ }
+}
+
bool OurReader::match(const Char* pattern, int patternLength) {
if (end_ - current_ < patternLength)
return false;
while ((current_ + 1) < end_) {
Char c = getNextChar();
- if (c == '*' && *current_ == '/') {
+ if (c == '*' && *current_ == '/')
break;
- } else if (c == '\n') {
+ if (c == '\n')
*containsNewLineResult = true;
- }
}
return getNextChar() == '/';
initialTokenOk = readToken(tokenName);
if (!initialTokenOk)
break;
- if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+ if (tokenName.type_ == tokenObjectEnd &&
+ (name.empty() ||
+ features_.allowTrailingCommas_)) // empty object or trailing comma
return true;
name.clear();
if (tokenName.type_ == tokenString) {
Value init(arrayValue);
currentValue().swapPayload(init);
currentValue().setOffsetStart(token.start_ - begin_);
- skipSpaces();
- if (current_ != end_ && *current_ == ']') // empty array
- {
- Token endArray;
- readToken(endArray);
- return true;
- }
int index = 0;
for (;;) {
+ skipSpaces();
+ if (current_ != end_ && *current_ == ']' &&
+ (index == 0 ||
+ (features_.allowTrailingCommas_ &&
+ !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
+ // comma
+ {
+ Token endArray;
+ readToken(endArray);
+ return true;
+ }
Value& value = currentValue()[index++];
nodes_.push(&value);
bool ok = readValue();
// then take the inverse. This assumes that minLargestInt is only a single
// power of 10 different in magnitude, which we check above. For the last
// digit, we take the modulus before negating for the same reason.
- static constexpr Value::LargestUInt negative_threshold =
+ static constexpr auto negative_threshold =
Value::LargestUInt(-(Value::minLargestInt / 10));
- static constexpr Value::UInt negative_last_digit =
+ static constexpr auto negative_last_digit =
Value::UInt(-(Value::minLargestInt % 10));
const Value::LargestUInt threshold =
if (c < '0' || c > '9')
return decodeDouble(token, decoded);
- const Value::UInt digit(static_cast<Value::UInt>(c - '0'));
+ const auto digit(static_cast<Value::UInt>(c - '0'));
if (value >= threshold) {
// We've hit or exceeded the max value divided by 10 (rounded down). If
// a) we've only just touched the limit, meaing value == threshold,
if (isNegative) {
// We use the same magnitude assumption here, just in case.
- const Value::UInt last_digit = static_cast<Value::UInt>(value % 10);
+ const auto last_digit = static_cast<Value::UInt>(value % 10);
decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
} else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
decoded = Value::LargestInt(value);
Location end = token.end_ - 1; // do not include '"'
while (current != end) {
Char c = *current++;
- if (c == '"') {
+ if (c == '"')
break;
- } else if (c == '\\') {
+ if (c == '\\') {
if (current == end)
return addError("Empty escape sequence in string", token, current);
Char escape = *current++;
bool collectComments = settings_["collectComments"].asBool();
OurFeatures features = OurFeatures::all();
features.allowComments_ = settings_["allowComments"].asBool();
+ features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
features.strictRoot_ = settings_["strictRoot"].asBool();
features.allowDroppedNullPlaceholders_ =
settings_["allowDroppedNullPlaceholders"].asBool();
features.failIfExtra_ = settings_["failIfExtra"].asBool();
features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+ features.skipBom_ = settings_["skipBom"].asBool();
return new OurCharReader(collectComments, features);
}
-static void getValidReaderKeys(std::set<String>* valid_keys) {
- valid_keys->clear();
- valid_keys->insert("collectComments");
- valid_keys->insert("allowComments");
- valid_keys->insert("strictRoot");
- valid_keys->insert("allowDroppedNullPlaceholders");
- valid_keys->insert("allowNumericKeys");
- valid_keys->insert("allowSingleQuotes");
- valid_keys->insert("stackLimit");
- valid_keys->insert("failIfExtra");
- valid_keys->insert("rejectDupKeys");
- valid_keys->insert("allowSpecialFloats");
-}
+
bool CharReaderBuilder::validate(Json::Value* invalid) const {
- Json::Value my_invalid;
- if (!invalid)
- invalid = &my_invalid; // so we do not need to test for NULL
- Json::Value& inv = *invalid;
- std::set<String> valid_keys;
- getValidReaderKeys(&valid_keys);
- Value::Members keys = settings_.getMemberNames();
- size_t n = keys.size();
- for (size_t i = 0; i < n; ++i) {
- String const& key = keys[i];
- if (valid_keys.find(key) == valid_keys.end()) {
- inv[key] = settings_[key];
- }
+ static const auto& valid_keys = *new std::set<String>{
+ "collectComments",
+ "allowComments",
+ "allowTrailingCommas",
+ "strictRoot",
+ "allowDroppedNullPlaceholders",
+ "allowNumericKeys",
+ "allowSingleQuotes",
+ "stackLimit",
+ "failIfExtra",
+ "rejectDupKeys",
+ "allowSpecialFloats",
+ "skipBom",
+ };
+ for (auto si = settings_.begin(); si != settings_.end(); ++si) {
+ auto key = si.name();
+ if (valid_keys.count(key))
+ continue;
+ if (invalid)
+ (*invalid)[std::move(key)] = *si;
+ else
+ return false;
}
- return inv.empty();
+ return invalid ? invalid->empty() : true;
}
+
Value& CharReaderBuilder::operator[](const String& key) {
return settings_[key];
}
void CharReaderBuilder::strictMode(Json::Value* settings) {
//! [CharReaderBuilderStrictMode]
(*settings)["allowComments"] = false;
+ (*settings)["allowTrailingCommas"] = false;
(*settings)["strictRoot"] = true;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["failIfExtra"] = true;
(*settings)["rejectDupKeys"] = true;
(*settings)["allowSpecialFloats"] = false;
+ (*settings)["skipBom"] = true;
//! [CharReaderBuilderStrictMode]
}
// static
//! [CharReaderBuilderDefaults]
(*settings)["collectComments"] = true;
(*settings)["allowComments"] = true;
+ (*settings)["allowTrailingCommas"] = true;
(*settings)["strictRoot"] = false;
(*settings)["allowDroppedNullPlaceholders"] = false;
(*settings)["allowNumericKeys"] = false;
(*settings)["failIfExtra"] = false;
(*settings)["rejectDupKeys"] = false;
(*settings)["allowSpecialFloats"] = false;
+ (*settings)["skipBom"] = true;
//! [CharReaderBuilderDefaults]
}
};
// Defines a char buffer for use with uintToString().
-typedef char UIntToStringBuffer[uintToStringBufferSize];
+using UIntToStringBuffer = char[uintToStringBufferSize];
/** Converts an unsigned integer to string.
* @param value Unsigned integer to convert to string
#include <json/value.h>
#include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
#include <cassert>
#include <cmath>
+#include <cstddef>
#include <cstring>
+#include <iostream>
#include <sstream>
#include <utility>
-#ifdef JSON_USE_CPPTL
-#include <cpptl/conststring.h>
-#endif
-#include <algorithm> // min()
-#include <cstddef> // size_t
// Provide implementation equivalent of std::snprintf for older _MSC compilers
#if defined(_MSC_VER) && _MSC_VER < 1900
if (length >= static_cast<size_t>(Value::maxInt))
length = Value::maxInt - 1;
- char* newString = static_cast<char*>(malloc(length + 1));
+ auto newString = static_cast<char*>(malloc(length + 1));
if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateStringValue(): "
"Failed to allocate string value buffer");
sizeof(unsigned) - 1U,
"in Json::Value::duplicateAndPrefixStringValue(): "
"length too big for prefixing");
- unsigned actualLength = length + static_cast<unsigned>(sizeof(unsigned)) + 1U;
- char* newString = static_cast<char*>(malloc(actualLength));
+ size_t actualLength = sizeof(length) + length + 1;
+ auto newString = static_cast<char*>(malloc(actualLength));
if (newString == nullptr) {
throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
"Failed to allocate string value buffer");
#if JSON_USE_EXCEPTION
Exception::Exception(String msg) : msg_(std::move(msg)) {}
-Exception::~Exception() JSONCPP_NOEXCEPT = default;
-char const* Exception::what() const JSONCPP_NOEXCEPT { return msg_.c_str(); }
+Exception::~Exception() noexcept = default;
+char const* Exception::what() const noexcept { return msg_.c_str(); }
RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
LogicError::LogicError(String const& msg) : Exception(msg) {}
JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
throw LogicError(msg);
}
#else // !JSON_USE_EXCEPTION
-JSONCPP_NORETURN void throwRuntimeError(String const& msg) { abort(); }
-JSONCPP_NORETURN void throwLogicError(String const& msg) { abort(); }
+JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
+ std::cerr << msg << std::endl;
+ abort();
+}
+JSONCPP_NORETURN void throwLogicError(String const& msg) {
+ std::cerr << msg << std::endl;
+ abort();
+}
#endif
// //////////////////////////////////////////////////////////////////
value_.string_ = const_cast<char*>(value.c_str());
}
-#ifdef JSON_USE_CPPTL
-Value::Value(const CppTL::ConstString& value) {
- initBasic(stringValue, true);
- value_.string_ = duplicateAndPrefixStringValue(
- value, static_cast<unsigned>(value.length()));
-}
-#endif
-
Value::Value(bool value) {
initBasic(booleanValue);
value_.bool_ = value;
}
case arrayValue:
case objectValue: {
- int delta = int(value_.map_->size() - other.value_.map_->size());
- if (delta)
- return delta < 0;
+ auto thisSize = value_.map_->size();
+ auto otherSize = other.value_.map_->size();
+ if (thisSize != otherSize)
+ return thisSize < otherSize;
return (*value_.map_) < (*other.value_.map_);
}
default:
}
}
-#ifdef JSON_USE_CPPTL
-CppTL::ConstString Value::asConstString() const {
- unsigned len;
- char const* str;
- decodePrefixedString(isAllocated(), value_.string_, &len, &str);
- return CppTL::ConstString(str, len);
-}
-#endif
-
Value::Int Value::asInt() const {
switch (type()) {
case intValue:
bool Value::empty() const {
if (isNull() || isArray() || isObject())
return size() == 0U;
- else
- return false;
+ return false;
}
Value::operator bool() const { return !isNull(); }
return resolveReference(key.c_str());
}
-#ifdef JSON_USE_CPPTL
-Value& Value::operator[](const CppTL::ConstString& key) {
- return resolveReference(key.c_str(), key.end_c_str());
-}
-Value const& Value::operator[](CppTL::ConstString const& key) const {
- Value const* found = find(key.c_str(), key.end_c_str());
- if (!found)
- return nullSingleton();
- return *found;
-}
-#endif
-
Value& Value::append(const Value& value) { return append(Value(value)); }
Value& Value::append(Value&& value) {
return this->value_.map_->emplace(size(), std::move(value)).first->second;
}
-bool Value::insert(ArrayIndex index, Value newValue) {
+bool Value::insert(ArrayIndex index, const Value& newValue) {
+ return insert(index, Value(newValue));
+}
+
+bool Value::insert(ArrayIndex index, Value&& newValue) {
JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
"in Json::Value::insert: requires arrayValue");
ArrayIndex length = size();
if (index > length) {
return false;
- } else {
- for (ArrayIndex i = length; i > index; i--) {
- (*this)[i] = std::move((*this)[i - 1]);
- }
- (*this)[index] = std::move(newValue);
- return true;
}
+ for (ArrayIndex i = length; i > index; i--) {
+ (*this)[i] = std::move((*this)[i - 1]);
+ }
+ (*this)[index] = std::move(newValue);
+ return true;
}
Value Value::get(char const* begin, char const* end,
return true;
}
-#ifdef JSON_USE_CPPTL
-Value Value::get(const CppTL::ConstString& key,
- const Value& defaultValue) const {
- return get(key.c_str(), key.end_c_str(), defaultValue);
-}
-#endif
-
bool Value::isMember(char const* begin, char const* end) const {
Value const* value = find(begin, end);
return nullptr != value;
return isMember(key.data(), key.data() + key.length());
}
-#ifdef JSON_USE_CPPTL
-bool Value::isMember(const CppTL::ConstString& key) const {
- return isMember(key.c_str(), key.end_c_str());
-}
-#endif
-
Value::Members Value::getMemberNames() const {
JSON_ASSERT_MESSAGE(
type() == nullValue || type() == objectValue,
}
return members;
}
-//
-//# ifdef JSON_USE_CPPTL
-// EnumMemberNames
-// Value::enumMemberNames() const
-//{
-// if ( type() == objectValue )
-// {
-// return CppTL::Enum::any( CppTL::Enum::transform(
-// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
-// MemberNamesTransform() ) );
-// }
-// return EnumMemberNames();
-//}
-//
-//
-// EnumValues
-// Value::enumValues() const
-//{
-// if ( type() == objectValue || type() == arrayValue )
-// return CppTL::Enum::anyValues( *(value_.map_),
-// CppTL::Type<const Value &>() );
-// return EnumValues();
-//}
-//
-//# endif
static bool IsIntegral(double d) {
double integral_part;
ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance(const SelfType& other) const {
-#ifdef JSON_USE_CPPTL_SMALLMAP
- return other.current_ - current_;
-#else
// Iterator for null value are initialized using the default
// constructor, which initialize current_ to the default
// std::map::iterator. As begin() and end() are two instance
++myDistance;
}
return myDistance;
-#endif
}
bool ValueIteratorBase::isEqual(const SelfType& other) const {
#include "json_tool.h"
#include <json/writer.h>
#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
#include <cassert>
+#include <cctype>
#include <cstring>
#include <iomanip>
#include <memory>
#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
using StreamWriterPtr = std::unique_ptr<StreamWriter>;
#else
-typedef std::auto_ptr<StreamWriter> StreamWriterPtr;
+using StreamWriterPtr = std::auto_ptr<StreamWriter>;
#endif
String valueToString(LargestInt value) {
String valueToString(bool value) { return value ? "true" : "false"; }
-static bool isAnyCharRequiredQuoting(char const* s, size_t n) {
+static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
assert(s || !n);
- char const* const end = s + n;
- for (char const* cur = s; cur < end; ++cur) {
- if (*cur == '\\' || *cur == '\"' || *cur < ' ' ||
- static_cast<unsigned char>(*cur) < 0x80)
- return true;
- }
- return false;
+ return std::any_of(s, s + n, [](unsigned char c) {
+ return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
+ });
}
static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
return result;
}
+static void appendRaw(String& result, unsigned ch) {
+ result += static_cast<char>(ch);
+}
+
+static void appendHex(String& result, unsigned ch) {
+ result.append("\\u").append(toHex16Bit(ch));
+}
+
static String valueToQuotedStringN(const char* value, unsigned length,
bool emitUTF8 = false) {
if (value == nullptr)
return "";
- if (!isAnyCharRequiredQuoting(value, length))
+ if (!doesAnyCharRequireEscaping(value, length))
return String("\"") + value + "\"";
// We have to walk value and escape any special characters.
// Appending to String is not efficient, but this should be rare.
// sequence from occurring.
default: {
if (emitUTF8) {
- result += *c;
+ unsigned codepoint = static_cast<unsigned char>(*c);
+ if (codepoint < 0x20) {
+ appendHex(result, codepoint);
+ } else {
+ appendRaw(result, codepoint);
+ }
} else {
- unsigned int codepoint = utf8ToCodepoint(c, end);
- const unsigned int FIRST_NON_CONTROL_CODEPOINT = 0x20;
- const unsigned int LAST_NON_CONTROL_CODEPOINT = 0x7F;
- const unsigned int FIRST_SURROGATE_PAIR_CODEPOINT = 0x10000;
- // don't escape non-control characters
- // (short escape sequence are applied above)
- if (FIRST_NON_CONTROL_CODEPOINT <= codepoint &&
- codepoint <= LAST_NON_CONTROL_CODEPOINT) {
- result += static_cast<char>(codepoint);
- } else if (codepoint <
- FIRST_SURROGATE_PAIR_CODEPOINT) { // codepoint is in Basic
- // Multilingual Plane
- result += "\\u";
- result += toHex16Bit(codepoint);
- } else { // codepoint is not in Basic Multilingual Plane
- // convert to surrogate pair first
- codepoint -= FIRST_SURROGATE_PAIR_CODEPOINT;
- result += "\\u";
- result += toHex16Bit((codepoint >> 10) + 0xD800);
- result += "\\u";
- result += toHex16Bit((codepoint & 0x3FF) + 0xDC00);
+ unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c`
+ if (codepoint < 0x20) {
+ appendHex(result, codepoint);
+ } else if (codepoint < 0x80) {
+ appendRaw(result, codepoint);
+ } else if (codepoint < 0x10000) {
+ // Basic Multilingual Plane
+ appendHex(result, codepoint);
+ } else {
+ // Extended Unicode. Encode 20 bits as a surrogate pair.
+ codepoint -= 0x10000;
+ appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
+ appendHex(result, 0xdc00 + (codepoint & 0x3ff));
}
}
} break;
endingLineFeedSymbol, usf, emitUTF8, pre,
precisionType);
}
-static void getValidWriterKeys(std::set<String>* valid_keys) {
- valid_keys->clear();
- valid_keys->insert("indentation");
- valid_keys->insert("commentStyle");
- valid_keys->insert("enableYAMLCompatibility");
- valid_keys->insert("dropNullPlaceholders");
- valid_keys->insert("useSpecialFloats");
- valid_keys->insert("emitUTF8");
- valid_keys->insert("precision");
- valid_keys->insert("precisionType");
-}
+
bool StreamWriterBuilder::validate(Json::Value* invalid) const {
- Json::Value my_invalid;
- if (!invalid)
- invalid = &my_invalid; // so we do not need to test for NULL
- Json::Value& inv = *invalid;
- std::set<String> valid_keys;
- getValidWriterKeys(&valid_keys);
- Value::Members keys = settings_.getMemberNames();
- size_t n = keys.size();
- for (size_t i = 0; i < n; ++i) {
- String const& key = keys[i];
- if (valid_keys.find(key) == valid_keys.end()) {
- inv[key] = settings_[key];
- }
+ static const auto& valid_keys = *new std::set<String>{
+ "indentation",
+ "commentStyle",
+ "enableYAMLCompatibility",
+ "dropNullPlaceholders",
+ "useSpecialFloats",
+ "emitUTF8",
+ "precision",
+ "precisionType",
+ };
+ for (auto si = settings_.begin(); si != settings_.end(); ++si) {
+ auto key = si.name();
+ if (valid_keys.count(key))
+ continue;
+ if (invalid)
+ (*invalid)[std::move(key)] = *si;
+ else
+ return false;
}
- return inv.empty();
+ return invalid ? invalid->empty() : true;
}
+
Value& StreamWriterBuilder::operator[](const String& key) {
return settings_[key];
}
# vim: et ts=4 sts=4 sw=4 tw=0
-add_executable( jsoncpp_test
- jsontest.cpp
- jsontest.h
- fuzz.cpp
- fuzz.h
- main.cpp
- )
+add_executable(jsoncpp_test
+ jsontest.cpp
+ jsontest.h
+ fuzz.cpp
+ fuzz.h
+ main.cpp
+)
if(BUILD_SHARED_LIBS)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
- add_compile_definitions( JSON_DLL )
- else()
- add_definitions( -DJSON_DLL )
- endif()
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.12.0)
+ add_compile_definitions( JSON_DLL )
+ else()
+ add_definitions( -DJSON_DLL )
+ endif()
+ target_link_libraries(jsoncpp_test jsoncpp_lib)
+else()
+ target_link_libraries(jsoncpp_test jsoncpp_static)
endif()
-target_link_libraries(jsoncpp_test jsoncpp_lib)
# another way to solve issue #90
#set_target_properties(jsoncpp_test PROPERTIES COMPILE_FLAGS -ffloat-store)
+## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp
+add_test(NAME jsoncpp_test
+ COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>
+)
+set_target_properties(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)
+
# Run unit tests in post-build
# (default cmake workflow hides away the test result into a file, resulting in poor dev workflow?!?)
if(JSONCPP_WITH_POST_BUILD_UNITTEST)
- if(BUILD_SHARED_LIBS)
- # First, copy the shared lib, for Microsoft.
- # Then, run the test executable.
- add_custom_command( TARGET jsoncpp_test
- POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:jsoncpp_lib> $<TARGET_FILE_DIR:jsoncpp_test>
- COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>)
- else(BUILD_SHARED_LIBS)
- # Just run the test executable.
- add_custom_command( TARGET jsoncpp_test
- POST_BUILD
- COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>)
- endif()
- ## Create tests for dashboard submission, allows easy review of CI results https://my.cdash.org/index.php?project=jsoncpp
- add_test(NAME jsoncpp_test
- COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>
+ add_custom_command(TARGET jsoncpp_test
+ POST_BUILD
+ COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:jsoncpp_test>
)
endif()
-
-set_target_properties(jsoncpp_test PROPERTIES OUTPUT_NAME jsoncpp_test)
#include <json/config.h>
#include <json/json.h>
#include <memory>
-#include <stdint.h>
#include <string>
namespace Json {
builder.settings_["rejectDupKeys_"] = hash_settings & (1 << 7);
builder.settings_["allowSpecialFloats_"] = hash_settings & (1 << 8);
builder.settings_["collectComments"] = hash_settings & (1 << 9);
+ builder.settings_["allowTrailingCommas_"] = hash_settings & (1 << 10);
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value root;
- const char* data_str = reinterpret_cast<const char*>(data);
+ const auto data_str = reinterpret_cast<const char*>(data);
try {
reader->parse(data_str, data_str + size, &root, nullptr);
} catch (Json::Exception const&) {
printf("All %zu tests passed\n", count);
}
return true;
- } else {
- for (auto& result : failures) {
- result.printFailure(count > 1);
- }
+ }
+ for (auto& result : failures) {
+ result.printFailure(count > 1);
+ }
- if (printSummary) {
- size_t const failedCount = failures.size();
- size_t const passedCount = count - failedCount;
- printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count,
- failedCount);
- }
- return false;
+ if (printSummary) {
+ size_t const failedCount = failures.size();
+ size_t const passedCount = count - failedCount;
+ printf("%zu/%zu tests passed (%zu failure(s))\n", passedCount, count,
+ failedCount);
}
+ return false;
}
bool Runner::testIndex(const Json::String& testName, size_t& indexOut) const {
if (opt == "--list-tests") {
listTests();
return 0;
- } else if (opt == "--test-auto") {
+ }
+ if (opt == "--test-auto") {
preventDialogOnCrash();
} else if (opt == "--test") {
++index;
/// Must be a POD to allow inline initialisation without stepping
/// into the debugger.
struct PredicateContext {
- typedef unsigned int Id;
+ using Id = unsigned int;
Id id_;
const char* file_;
unsigned int line_;
static Json::String indentText(const Json::String& text,
const Json::String& indent);
- typedef std::deque<Failure> Failures;
+ using Failures = std::deque<Failure>;
Failures failures_;
Json::String name_;
PredicateContext rootPredicateNode_;
};
/// Function pointer type for TestCase factory
-typedef TestCase* (*TestCaseFactory)();
+using TestCaseFactory = TestCase* (*)();
class Runner {
public:
static void preventDialogOnCrash();
private:
- typedef std::deque<TestCaseFactory> Factories;
+ using Factories = std::deque<TestCaseFactory>;
Factories tests_;
};
/// The predicate may do other assertions and be a member function of the
/// fixture.
#define JSONTEST_ASSERT_PRED(expr) \
- { \
+ do { \
JsonTest::PredicateContext _minitest_Context = { \
result_->predicateId_, __FILE__, __LINE__, #expr, NULL, NULL}; \
result_->predicateStackTail_->next_ = &_minitest_Context; \
result_->predicateStackTail_ = &_minitest_Context; \
(expr); \
result_->popPredicateContext(); \
- }
+ } while (0)
/// \brief Asserts that two values are equals.
#define JSONTEST_ASSERT_EQUAL(expected, actual) \
/// \brief Asserts that a given expression throws an exception
#define JSONTEST_ASSERT_THROWS(expr) \
- { \
+ do { \
bool _threw = false; \
try { \
expr; \
if (!_threw) \
result_->addFailure(__FILE__, __LINE__, \
"expected exception thrown: " #expr); \
- }
+ } while (0)
/// \brief Begin a fixture test case.
#define JSONTEST_FIXTURE(FixtureType, name) \
#include "jsontest.h"
#include <cmath>
#include <cstring>
+#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <json/config.h>
#include <json/json.h>
#include <limits>
+#include <memory>
#include <sstream>
#include <string>
+using CharReaderPtr = std::unique_ptr<Json::CharReader>;
+
// Make numeric limits more convenient to talk about.
// Assumes int type in 32 bits.
#define kint32max Json::Value::maxInt
struct ValueTest : JsonTest::TestCase {
Json::Value null_;
- Json::Value emptyArray_;
- Json::Value emptyObject_;
- Json::Value integer_;
- Json::Value unsignedInteger_;
- Json::Value smallUnsignedInteger_;
- Json::Value real_;
- Json::Value float_;
+ Json::Value emptyArray_{Json::arrayValue};
+ Json::Value emptyObject_{Json::objectValue};
+ Json::Value integer_{123456789};
+ Json::Value unsignedInteger_{34567890};
+ Json::Value smallUnsignedInteger_{Json::Value::UInt(Json::Value::maxInt)};
+ Json::Value real_{1234.56789};
+ Json::Value float_{0.00390625f};
Json::Value array1_;
Json::Value object1_;
- Json::Value emptyString_;
- Json::Value string1_;
- Json::Value string_;
- Json::Value true_;
- Json::Value false_;
-
- ValueTest()
- : emptyArray_(Json::arrayValue), emptyObject_(Json::objectValue),
- integer_(123456789), unsignedInteger_(34567890u),
- smallUnsignedInteger_(Json::Value::UInt(Json::Value::maxInt)),
- real_(1234.56789), float_(0.00390625f), emptyString_(""), string1_("a"),
- string_("sometext with space"), true_(true), false_(false) {
+ Json::Value emptyString_{""};
+ Json::Value string1_{"a"};
+ Json::Value string_{"sometext with space"};
+ Json::Value true_{true};
+ Json::Value false_{false};
+
+ ValueTest() {
array1_.append(1234);
object1_["id"] = 1234;
}
};
Json::String ValueTest::normalizeFloatingPointStr(const Json::String& s) {
- Json::String::size_type index = s.find_last_of("eE");
- if (index != Json::String::npos) {
- Json::String::size_type hasSign =
- (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
- Json::String::size_type exponentStartIndex = index + 1 + hasSign;
- Json::String normalized = s.substr(0, exponentStartIndex);
- Json::String::size_type indexDigit =
- s.find_first_not_of('0', exponentStartIndex);
- Json::String exponent = "0";
- if (indexDigit != Json::String::npos) // There is an exponent different
- // from 0
- {
- exponent = s.substr(indexDigit);
- }
- return normalized + exponent;
+ auto index = s.find_last_of("eE");
+ if (index == s.npos)
+ return s;
+ std::size_t signWidth = (s[index + 1] == '+' || s[index + 1] == '-') ? 1 : 0;
+ auto exponentStartIndex = index + 1 + signWidth;
+ Json::String normalized = s.substr(0, exponentStartIndex);
+ auto indexDigit = s.find_first_not_of('0', exponentStartIndex);
+ Json::String exponent = "0";
+ if (indexDigit != s.npos) { // nonzero exponent
+ exponent = s.substr(indexDigit);
}
- return s;
+ return normalized + exponent;
}
JSONTEST_FIXTURE_LOCAL(ValueTest, checkNormalizeFloatingPointStr) {
- JSONTEST_ASSERT_STRING_EQUAL("0.0", normalizeFloatingPointStr("0.0"));
- JSONTEST_ASSERT_STRING_EQUAL("0e0", normalizeFloatingPointStr("0e0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0", normalizeFloatingPointStr("1234.0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0e0",
- normalizeFloatingPointStr("1234.0e0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0e-1",
- normalizeFloatingPointStr("1234.0e-1"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0e+0",
- normalizeFloatingPointStr("1234.0e+0"));
- JSONTEST_ASSERT_STRING_EQUAL("1234.0e+1",
- normalizeFloatingPointStr("1234.0e+001"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e-1", normalizeFloatingPointStr("1234e-1"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+0",
- normalizeFloatingPointStr("1234e+000"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+1",
- normalizeFloatingPointStr("1234e+001"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e10", normalizeFloatingPointStr("1234e10"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e10",
- normalizeFloatingPointStr("1234e010"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+10",
- normalizeFloatingPointStr("1234e+010"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e-10",
- normalizeFloatingPointStr("1234e-010"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e+100",
- normalizeFloatingPointStr("1234e+100"));
- JSONTEST_ASSERT_STRING_EQUAL("1234e-100",
- normalizeFloatingPointStr("1234e-100"));
+ struct TestData {
+ std::string in;
+ std::string out;
+ } const testData[] = {
+ {"0.0", "0.0"},
+ {"0e0", "0e0"},
+ {"1234.0", "1234.0"},
+ {"1234.0e0", "1234.0e0"},
+ {"1234.0e-1", "1234.0e-1"},
+ {"1234.0e+0", "1234.0e+0"},
+ {"1234.0e+001", "1234.0e+1"},
+ {"1234e-1", "1234e-1"},
+ {"1234e+000", "1234e+0"},
+ {"1234e+001", "1234e+1"},
+ {"1234e10", "1234e10"},
+ {"1234e010", "1234e10"},
+ {"1234e+010", "1234e+10"},
+ {"1234e-010", "1234e-10"},
+ {"1234e+100", "1234e+100"},
+ {"1234e-100", "1234e-100"},
+ };
+ for (const auto& td : testData) {
+ JSONTEST_ASSERT_STRING_EQUAL(normalizeFloatingPointStr(td.in), td.out);
+ }
}
JSONTEST_FIXTURE_LOCAL(ValueTest, memberCount) {
}
vec.push_back(&array[4]);
// insert rvalue at the tail
- Json::Value index5("index5");
- JSONTEST_ASSERT(array.insert(5, std::move(index5)));
+ JSONTEST_ASSERT(array.insert(5, "index5"));
JSONTEST_ASSERT_EQUAL(Json::Value("index3"), array[0]);
JSONTEST_ASSERT_EQUAL(Json::Value("index0"), array[1]);
JSONTEST_ASSERT_EQUAL(Json::Value("index4"), array[2]);
JSONTEST_ASSERT_PRED(checkConstMemberCount(value, expectedCount));
}
-ValueTest::IsCheck::IsCheck()
-
- = default;
+ValueTest::IsCheck::IsCheck() = default;
void ValueTest::checkIs(const Json::Value& value, const IsCheck& check) {
JSONTEST_ASSERT_EQUAL(check.isObject_, value.isObject());
JSONTEST_FIXTURE_LOCAL(ValueTest, WideString) {
// https://github.com/open-source-parsers/jsoncpp/issues/756
- const std::string uni = u8"式,进"; // "\u5f0f\uff0c\u8fdb"
+ const std::string uni = u8"\u5f0f\uff0c\u8fdb"; // "式,进"
std::string styled;
{
Json::Value v;
Json::String result = Json::writeString(wbuilder, val);
JSONTEST_ASSERT_STRING_EQUAL(expected, result);
Json::String res2 = val.toStyledString();
- Json::String exp2 = "";
+ Json::String exp2;
exp2 += expected;
exp2 += "\n";
JSONTEST_ASSERT_STRING_EQUAL(exp2, res2);
JSONTEST_FIXTURE_LOCAL(StreamWriterTest, writeZeroes) {
Json::String binary("hi", 3); // include trailing 0
JSONTEST_ASSERT_EQUAL(3, binary.length());
- Json::String expected("\"hi\\u0000\""); // unicoded zero
+ Json::String expected(R"("hi\u0000")"); // unicoded zero
Json::StreamWriterBuilder b;
{
Json::Value root;
"\"\\t\\n\\ud806\\udca1=\\u0133\\ud82c\\udd1b\\uff67\"\n}");
}
-struct ReaderTest : JsonTest::TestCase {};
+// Control chars should be escaped regardless of UTF-8 input encoding.
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeControlCharacters) {
+ auto uEscape = [](unsigned ch) {
+ static const char h[] = "0123456789abcdef";
+ std::string r = "\\u";
+ r += h[(ch >> (3 * 4)) & 0xf];
+ r += h[(ch >> (2 * 4)) & 0xf];
+ r += h[(ch >> (1 * 4)) & 0xf];
+ r += h[(ch >> (0 * 4)) & 0xf];
+ return r;
+ };
+ auto shortEscape = [](unsigned ch) -> const char* {
+ switch (ch) {
+ case '\"':
+ return "\\\"";
+ case '\\':
+ return "\\\\";
+ case '\b':
+ return "\\b";
+ case '\f':
+ return "\\f";
+ case '\n':
+ return "\\n";
+ case '\r':
+ return "\\r";
+ case '\t':
+ return "\\t";
+ default:
+ return nullptr;
+ }
+ };
+
+ Json::StreamWriterBuilder b;
+
+ for (bool emitUTF8 : {true, false}) {
+ b.settings_["emitUTF8"] = emitUTF8;
+
+ for (unsigned i = 0; i != 0x100; ++i) {
+ if (!emitUTF8 && i >= 0x80)
+ break; // The algorithm would try to parse UTF-8, so stop here.
+
+ std::string raw({static_cast<char>(i)});
+ std::string esc = raw;
+ if (i < 0x20)
+ esc = uEscape(i);
+ if (const char* shEsc = shortEscape(i))
+ esc = shEsc;
+
+ // std::cout << "emit=" << emitUTF8 << ", i=" << std::hex << i << std::dec
+ // << std::endl;
+
+ Json::Value root;
+ root["test"] = raw;
+ JSONTEST_ASSERT_STRING_EQUAL(
+ std::string("{\n\t\"test\" : \"").append(esc).append("\"\n}"),
+ Json::writeString(b, root))
+ << ", emit=" << emitUTF8 << ", i=" << i << ", raw=\"" << raw << "\""
+ << ", esc=\"" << esc << "\"";
+ }
+ }
+}
+
+#ifdef _WIN32
+JSONTEST_FIXTURE_LOCAL(StreamWriterTest, escapeTabCharacterWindows) {
+ // Get the current locale before changing it
+ std::string currentLocale = setlocale(LC_ALL, NULL);
+ setlocale(LC_ALL, "English_United States.1252");
-JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) {
- Json::Reader reader;
Json::Value root;
- bool ok = reader.parse("{ \"property\" : \"value\" }", root);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages().empty());
- JSONTEST_ASSERT(reader.getStructuredErrors().empty());
+ root["test"] = "\tTabTesting\t";
+
+ Json::StreamWriterBuilder b;
+
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : "
+ "\"\\tTabTesting\\t\"\n}");
+
+ b.settings_["emitUTF8"] = true;
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : "
+ "\"\\tTabTesting\\t\"\n}");
+
+ b.settings_["emitUTF8"] = false;
+ JSONTEST_ASSERT(Json::writeString(b, root) == "{\n\t\"test\" : "
+ "\"\\tTabTesting\\t\"\n}");
+
+ // Restore the locale
+ if (!currentLocale.empty())
+ setlocale(LC_ALL, currentLocale.c_str());
}
+#endif
-JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) {
- Json::Reader reader;
+struct ReaderTest : JsonTest::TestCase {
+ void setStrictMode() {
+ reader = std::unique_ptr<Json::Reader>(
+ new Json::Reader(Json::Features{}.strictMode()));
+ }
+
+ void setFeatures(Json::Features& features) {
+ reader = std::unique_ptr<Json::Reader>(new Json::Reader(features));
+ }
+
+ void checkStructuredErrors(
+ const std::vector<Json::Reader::StructuredError>& actual,
+ const std::vector<Json::Reader::StructuredError>& expected) {
+ JSONTEST_ASSERT_EQUAL(expected.size(), actual.size());
+ for (size_t i = 0; i < actual.size(); ++i) {
+ const auto& a = actual[i];
+ const auto& e = expected[i];
+ JSONTEST_ASSERT_EQUAL(e.offset_start, a.offset_start) << i;
+ JSONTEST_ASSERT_EQUAL(e.offset_limit, a.offset_limit) << i;
+ JSONTEST_ASSERT_EQUAL(e.message, a.message) << i;
+ }
+ }
+
+ template <typename Input> void checkParse(Input&& input) {
+ JSONTEST_ASSERT(reader->parse(input, root));
+ }
+
+ template <typename Input>
+ void
+ checkParse(Input&& input,
+ const std::vector<Json::Reader::StructuredError>& structured) {
+ JSONTEST_ASSERT(!reader->parse(input, root));
+ checkStructuredErrors(reader->getStructuredErrors(), structured);
+ }
+
+ template <typename Input>
+ void checkParse(Input&& input,
+ const std::vector<Json::Reader::StructuredError>& structured,
+ const std::string& formatted) {
+ checkParse(input, structured);
+ JSONTEST_ASSERT_EQUAL(formatted, reader->getFormattedErrorMessages());
+ }
+
+ std::unique_ptr<Json::Reader> reader{new Json::Reader()};
Json::Value root;
- bool ok = reader.parse("{ /*commentBeforeValue*/"
- " \"property\" : \"value\" }"
- "//commentAfterValue\n",
- root);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages().empty());
- JSONTEST_ASSERT(reader.getStructuredErrors().empty());
+};
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrors) {
+ checkParse(R"({ "property" : "value" })");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseObject) {
+ checkParse(R"({"property"})",
+ {{11, 12, "Missing ':' after object member name"}},
+ "* Line 1, Column 12\n Missing ':' after object member name\n");
+ checkParse(
+ R"({"property" : "value" )",
+ {{22, 22, "Missing ',' or '}' in object declaration"}},
+ "* Line 1, Column 23\n Missing ',' or '}' in object declaration\n");
+ checkParse(R"({"property" : "value", )",
+ {{23, 23, "Missing '}' or object member name"}},
+ "* Line 1, Column 24\n Missing '}' or object member name\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseArray) {
+ checkParse(
+ R"([ "value" )", {{10, 10, "Missing ',' or ']' in array declaration"}},
+ "* Line 1, Column 11\n Missing ',' or ']' in array declaration\n");
+ checkParse(
+ R"([ "value1" "value2" ] )",
+ {{11, 19, "Missing ',' or ']' in array declaration"}},
+ "* Line 1, Column 12\n Missing ',' or ']' in array declaration\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseString) {
+ checkParse(R"([ "\u8a2a" ])");
+ checkParse(
+ R"([ "\ud801" ])",
+ {{2, 10,
+ "additional six characters expected to parse unicode surrogate "
+ "pair."}},
+ "* Line 1, Column 3\n"
+ " additional six characters expected to parse unicode surrogate pair.\n"
+ "See Line 1, Column 10 for detail.\n");
+ checkParse(R"([ "\ud801\d1234" ])",
+ {{2, 16,
+ "expecting another \\u token to begin the "
+ "second half of a unicode surrogate pair"}},
+ "* Line 1, Column 3\n"
+ " expecting another \\u token to begin the "
+ "second half of a unicode surrogate pair\n"
+ "See Line 1, Column 12 for detail.\n");
+ checkParse(R"([ "\ua3t@" ])",
+ {{2, 10,
+ "Bad unicode escape sequence in string: "
+ "hexadecimal digit expected."}},
+ "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: "
+ "hexadecimal digit expected.\n"
+ "See Line 1, Column 9 for detail.\n");
+ checkParse(
+ R"([ "\ua3t" ])",
+ {{2, 9, "Bad unicode escape sequence in string: four digits expected."}},
+ "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: four digits expected.\n"
+ "See Line 1, Column 6 for detail.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseComment) {
+ checkParse(
+ R"({ /*commentBeforeValue*/ "property" : "value" }//commentAfterValue)"
+ "\n");
+ checkParse(" true //comment1\n//comment2\r//comment3\r\n");
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, streamParseWithNoErrors) {
- Json::Reader reader;
- std::string styled = "{ \"property\" : \"value\" }";
+ std::string styled = R"({ "property" : "value" })";
std::istringstream iss(styled);
- Json::Value root;
- bool ok = reader.parse(iss, root);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages().empty());
- JSONTEST_ASSERT(reader.getStructuredErrors().empty());
+ checkParse(iss);
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithNoErrorsTestingOffsets) {
- Json::Reader reader;
- Json::Value root;
- bool ok = reader.parse("{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
- "{ \"nested\" : -6.2e+15, \"bool\" : true}, \"null\" :"
- " null, \"false\" : false }",
- root);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages().empty());
- JSONTEST_ASSERT(reader.getStructuredErrors().empty());
- JSONTEST_ASSERT(root["property"].getOffsetStart() == 15);
- JSONTEST_ASSERT(root["property"].getOffsetLimit() == 34);
- JSONTEST_ASSERT(root["property"][0].getOffsetStart() == 16);
- JSONTEST_ASSERT(root["property"][0].getOffsetLimit() == 23);
- JSONTEST_ASSERT(root["property"][1].getOffsetStart() == 25);
- JSONTEST_ASSERT(root["property"][1].getOffsetLimit() == 33);
- JSONTEST_ASSERT(root["obj"].getOffsetStart() == 44);
- JSONTEST_ASSERT(root["obj"].getOffsetLimit() == 81);
- JSONTEST_ASSERT(root["obj"]["nested"].getOffsetStart() == 57);
- JSONTEST_ASSERT(root["obj"]["nested"].getOffsetLimit() == 65);
- JSONTEST_ASSERT(root["obj"]["bool"].getOffsetStart() == 76);
- JSONTEST_ASSERT(root["obj"]["bool"].getOffsetLimit() == 80);
- JSONTEST_ASSERT(root["null"].getOffsetStart() == 92);
- JSONTEST_ASSERT(root["null"].getOffsetLimit() == 96);
- JSONTEST_ASSERT(root["false"].getOffsetStart() == 108);
- JSONTEST_ASSERT(root["false"].getOffsetLimit() == 113);
- JSONTEST_ASSERT(root.getOffsetStart() == 0);
- JSONTEST_ASSERT(root.getOffsetLimit() == 115);
+ checkParse(R"({)"
+ R"( "property" : ["value", "value2"],)"
+ R"( "obj" : { "nested" : -6.2e+15, "bool" : true},)"
+ R"( "null" : null,)"
+ R"( "false" : false)"
+ R"( })");
+ auto checkOffsets = [&](const Json::Value& v, int start, int limit) {
+ JSONTEST_ASSERT_EQUAL(start, v.getOffsetStart());
+ JSONTEST_ASSERT_EQUAL(limit, v.getOffsetLimit());
+ };
+ checkOffsets(root, 0, 115);
+ checkOffsets(root["property"], 15, 34);
+ checkOffsets(root["property"][0], 16, 23);
+ checkOffsets(root["property"][1], 25, 33);
+ checkOffsets(root["obj"], 44, 81);
+ checkOffsets(root["obj"]["nested"], 57, 65);
+ checkOffsets(root["obj"]["bool"], 76, 80);
+ checkOffsets(root["null"], 92, 96);
+ checkOffsets(root["false"], 108, 113);
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithOneError) {
- Json::Reader reader;
- Json::Value root;
- bool ok = reader.parse("{ \"property\" :: \"value\" }", root);
- JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
- "* Line 1, Column 15\n Syntax error: value, object or array "
- "expected.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 14);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 15);
- JSONTEST_ASSERT(errors.at(0).message ==
- "Syntax error: value, object or array expected.");
+ checkParse(R"({ "property" :: "value" })",
+ {{14, 15, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 15\n Syntax error: value, object or array "
+ "expected.\n");
+ checkParse("s", {{0, 1, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 1\n Syntax error: value, object or array "
+ "expected.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, parseSpecialFloat) {
+ checkParse(R"({ "a" : Infi })",
+ {{8, 9, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 9\n Syntax error: value, object or array "
+ "expected.\n");
+ checkParse(R"({ "a" : Infiniaa })",
+ {{8, 9, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 9\n Syntax error: value, object or array "
+ "expected.\n");
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, strictModeParseNumber) {
- Json::Features feature;
- Json::Reader reader(feature.strictMode());
- Json::Value root;
- bool ok = reader.parse("123", root);
- JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
- "* Line 1, Column 1\n"
- " A valid JSON document must be either an array or"
- " an object value.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 0);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 3);
- JSONTEST_ASSERT(errors.at(0).message ==
- "A valid JSON document must be either an array or"
- " an object value.");
+ setStrictMode();
+ checkParse(
+ "123",
+ {{0, 3,
+ "A valid JSON document must be either an array or an object value."}},
+ "* Line 1, Column 1\n"
+ " A valid JSON document must be either an array or an object value.\n");
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseChineseWithOneError) {
- Json::Reader reader;
- Json::Value root;
- bool ok = reader.parse("{ \"pr佐藤erty\" :: \"value\" }", root);
- JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
- "* Line 1, Column 19\n Syntax error: value, object or array "
- "expected.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 18);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 19);
- JSONTEST_ASSERT(errors.at(0).message ==
- "Syntax error: value, object or array expected.");
+ checkParse(R"({ "pr)"
+ u8"\u4f50\u85e4" // 佐藤
+ R"(erty" :: "value" })",
+ {{18, 19, "Syntax error: value, object or array expected."}},
+ "* Line 1, Column 19\n Syntax error: value, object or array "
+ "expected.\n");
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, parseWithDetailError) {
- Json::Reader reader;
- Json::Value root;
- bool ok = reader.parse("{ \"property\" : \"v\\alue\" }", root);
- JSONTEST_ASSERT(!ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
- "* Line 1, Column 16\n Bad escape sequence in string\nSee "
- "Line 1, Column 20 for detail.\n");
- std::vector<Json::Reader::StructuredError> errors =
- reader.getStructuredErrors();
- JSONTEST_ASSERT(errors.size() == 1);
- JSONTEST_ASSERT(errors.at(0).offset_start == 15);
- JSONTEST_ASSERT(errors.at(0).offset_limit == 23);
- JSONTEST_ASSERT(errors.at(0).message == "Bad escape sequence in string");
+ checkParse(R"({ "property" : "v\alue" })",
+ {{15, 23, "Bad escape sequence in string"}},
+ "* Line 1, Column 16\n"
+ " Bad escape sequence in string\n"
+ "See Line 1, Column 20 for detail.\n");
}
JSONTEST_FIXTURE_LOCAL(ReaderTest, pushErrorTest) {
- Json::Reader reader;
- Json::Value root;
- {
- bool ok = reader.parse("{ \"AUTHOR\" : 123 }", root);
- JSONTEST_ASSERT(ok);
- if (!root["AUTHOR"].isString()) {
- ok = reader.pushError(root["AUTHOR"], "AUTHOR must be a string");
- }
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
- "* Line 1, Column 14\n"
- " AUTHOR must be a string\n");
+ checkParse(R"({ "AUTHOR" : 123 })");
+ if (!root["AUTHOR"].isString()) {
+ JSONTEST_ASSERT(
+ reader->pushError(root["AUTHOR"], "AUTHOR must be a string"));
}
- {
- bool ok = reader.parse("{ \"AUTHOR\" : 123 }", root);
- JSONTEST_ASSERT(ok);
- if (!root["AUTHOR"].isString()) {
- ok = reader.pushError(root["AUTHOR"], "AUTHOR must be a string",
- root["AUTHOR"]);
- }
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(reader.getFormattedErrorMessages() ==
- "* Line 1, Column 14\n"
- " AUTHOR must be a string\n"
- "See Line 1, Column 14 for detail.\n");
+ JSONTEST_ASSERT_STRING_EQUAL(reader->getFormattedErrorMessages(),
+ "* Line 1, Column 14\n"
+ " AUTHOR must be a string\n");
+
+ checkParse(R"({ "AUTHOR" : 123 })");
+ if (!root["AUTHOR"].isString()) {
+ JSONTEST_ASSERT(reader->pushError(root["AUTHOR"], "AUTHOR must be a string",
+ root["AUTHOR"]));
}
+ JSONTEST_ASSERT_STRING_EQUAL(reader->getFormattedErrorMessages(),
+ "* Line 1, Column 14\n"
+ " AUTHOR must be a string\n"
+ "See Line 1, Column 14 for detail.\n");
+}
+
+JSONTEST_FIXTURE_LOCAL(ReaderTest, allowNumericKeysTest) {
+ Json::Features features;
+ features.allowNumericKeys_ = true;
+ setFeatures(features);
+ checkParse(R"({ 123 : "abc" })");
}
struct CharReaderTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrors) {
Json::CharReaderBuilder b;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
Json::Value root;
- char const doc[] = "{ \"property\" : \"value\" }";
+ char const doc[] = R"({ "property" : "value" })";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty());
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithNoErrorsTestingOffsets) {
Json::CharReaderBuilder b;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
Json::Value root;
char const doc[] = "{ \"property\" : [\"value\", \"value2\"], \"obj\" : "
- "{ \"nested\" : -6.2e+15, \"bool\" : true}, \"null\" : "
- "null, \"false\" : false }";
+ "{ \"nested\" : -6.2e+15, \"num\" : +123, \"bool\" : "
+ "true}, \"null\" : null, \"false\" : false }";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty());
- delete reader;
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseNumber) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::String errs;
+ Json::Value root;
+ {
+ // if intvalue > threshold, treat the number as a double.
+ // 21 digits
+ char const doc[] = "[111111111111111111111]";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL(1.1111111111111111e+020, root[0]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseString) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "[\"\"]";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("", root[0]);
+ }
+ {
+ char const doc[] = R"(["\u8A2a"])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL(u8"\u8A2a", root[0].asString()); // "訪"
+ }
+ {
+ char const doc[] = R"([ "\uD801" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
+ " additional six characters expected to "
+ "parse unicode surrogate pair.\n"
+ "See Line 1, Column 10 for detail.\n");
+ }
+ {
+ char const doc[] = R"([ "\uD801\d1234" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
+ " expecting another \\u token to begin the "
+ "second half of a unicode surrogate pair\n"
+ "See Line 1, Column 12 for detail.\n");
+ }
+ {
+ char const doc[] = R"([ "\ua3t@" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: "
+ "hexadecimal digit expected.\n"
+ "See Line 1, Column 9 for detail.\n");
+ }
+ {
+ char const doc[] = R"([ "\ua3t" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(
+ errs ==
+ "* Line 1, Column 3\n"
+ " Bad unicode escape sequence in string: four digits expected.\n"
+ "See Line 1, Column 6 for detail.\n");
+ }
+ {
+ b.settings_["allowSingleQuotes"] = true;
+ CharReaderPtr charreader(b.newCharReader());
+ char const doc[] = R"({'a': 'x\ty', "b":'x\\y'})";
+ bool ok = charreader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT_STRING_EQUAL("", errs);
+ JSONTEST_ASSERT_EQUAL(2u, root.size());
+ JSONTEST_ASSERT_STRING_EQUAL("x\ty", root["a"].asString());
+ JSONTEST_ASSERT_STRING_EQUAL("x\\y", root["b"].asString());
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseComment) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "//comment1\n { //comment2\n \"property\" :"
+ " \"value\" //comment3\n } //comment4\n";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+ {
+ char const doc[] = "{ \"property\" //comment\n : \"value\" }";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 14\n"
+ " Missing ':' after object member name\n");
+ }
+ {
+ char const doc[] = "//comment1\n [ //comment2\n \"value\" //comment3\n,"
+ " //comment4\n true //comment5\n ] //comment6\n";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_EQUAL("value", root[0]);
+ JSONTEST_ASSERT_EQUAL(true, root[1]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseObjectWithErrors) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = R"({ "property" : "value" )";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 24\n"
+ " Missing ',' or '}' in object declaration\n");
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+ {
+ char const doc[] = R"({ "property" : "value" ,)";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 25\n"
+ " Missing '}' or object member name\n");
+ JSONTEST_ASSERT_EQUAL("value", root["property"]);
+ }
+}
+
+JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseArrayWithErrors) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "[ \"value\" ";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 11\n"
+ " Missing ',' or ']' in array declaration\n");
+ JSONTEST_ASSERT_EQUAL("value", root[0]);
+ }
+ {
+ char const doc[] = R"([ "value1" "value2" ])";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(errs == "* Line 1, Column 12\n"
+ " Missing ',' or ']' in array declaration\n");
+ JSONTEST_ASSERT_EQUAL("value1", root[0]);
+ }
}
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithOneError) {
Json::CharReaderBuilder b;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
Json::Value root;
- char const doc[] = "{ \"property\" :: \"value\" }";
+ char const doc[] = R"({ "property" :: "value" })";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs ==
"* Line 1, Column 15\n Syntax error: value, object or array "
"expected.\n");
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseChineseWithOneError) {
Json::CharReaderBuilder b;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
Json::Value root;
char const doc[] = "{ \"pr佐藤erty\" :: \"value\" }";
JSONTEST_ASSERT(errs ==
"* Line 1, Column 19\n Syntax error: value, object or array "
"expected.\n");
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithDetailError) {
Json::CharReaderBuilder b;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
Json::Value root;
- char const doc[] = "{ \"property\" : \"v\\alue\" }";
+ char const doc[] = R"({ "property" : "v\alue" })";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
JSONTEST_ASSERT(errs ==
"* Line 1, Column 16\n Bad escape sequence in string\nSee "
"Line 1, Column 20 for detail.\n");
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(CharReaderTest, parseWithStackLimit) {
Json::CharReaderBuilder b;
Json::Value root;
- char const doc[] = "{ \"property\" : \"value\" }";
+ char const doc[] = R"({ "property" : "value" })";
{
b.settings_["stackLimit"] = 2;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL("value", root["property"]);
- delete reader;
}
{
b.settings_["stackLimit"] = 1;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
JSONTEST_ASSERT_THROWS(
reader->parse(doc, doc + std::strlen(doc), &root, &errs));
- delete reader;
}
}
JSONTEST_FIXTURE_LOCAL(CharReaderTest, testOperator) {
- const std::string styled = "{ \"property\" : \"value\" }";
+ const std::string styled = R"({ "property" : "value" })";
std::istringstream iss(styled);
Json::Value root;
iss >> root;
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] =
- "{ \"property\" : \"value\", \"key\" : \"val1\", \"key\" : \"val2\" }";
+ R"({ "property" : "value", "key" : "val1", "key" : "val2" })";
{
b.strictMode(&b.settings_);
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
" Duplicate key: 'key'\n",
errs);
JSONTEST_ASSERT_EQUAL("val1", root["key"]); // so far
- delete reader;
}
}
struct CharReaderFailIfExtraTest : JsonTest::TestCase {};
// This is interpreted as a string value followed by a colon.
Json::CharReaderBuilder b;
Json::Value root;
- char const doc[] = " \"property\" : \"value\" }";
+ char const doc[] = R"( "property" : "value" })";
{
b.settings_["failIfExtra"] = false;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty());
JSONTEST_ASSERT_EQUAL("property", root);
- delete reader;
}
{
b.settings_["failIfExtra"] = true;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
" Extra non-whitespace after JSON value.\n",
errs);
JSONTEST_ASSERT_EQUAL("property", root);
- delete reader;
}
{
b.strictMode(&b.settings_);
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
" Extra non-whitespace after JSON value.\n",
errs);
JSONTEST_ASSERT_EQUAL("property", root);
- delete reader;
}
{
b.strictMode(&b.settings_);
b.settings_["failIfExtra"] = false;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
" A valid JSON document must be either an array or an object value.\n",
errs);
JSONTEST_ASSERT_EQUAL("property", root);
- delete reader;
}
}
+
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, issue107) {
// This is interpreted as an int value followed by a colon.
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] = "1:2:3";
b.settings_["failIfExtra"] = true;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(!ok);
" Extra non-whitespace after JSON value.\n",
errs);
JSONTEST_ASSERT_EQUAL(1, root.asInt());
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterObject) {
Json::CharReaderBuilder b;
{
char const doc[] = "{ \"property\" : \"value\" } //trailing\n//comment\n";
b.settings_["failIfExtra"] = true;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root["property"]);
- delete reader;
}
}
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterArray) {
Json::Value root;
char const doc[] = "[ \"property\" , \"value\" ] //trailing\n//comment\n";
b.settings_["failIfExtra"] = true;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL("value", root[1u]);
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, commentAfterBool) {
Json::CharReaderBuilder b;
Json::Value root;
char const doc[] = " true /*trailing\ncomment*/";
b.settings_["failIfExtra"] = true;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::String errs;
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(true, root.asBool());
- delete reader;
}
-struct CharReaderAllowDropNullTest : JsonTest::TestCase {};
-JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
+JSONTEST_FIXTURE_LOCAL(CharReaderFailIfExtraTest, parseComment) {
Json::CharReaderBuilder b;
- b.settings_["allowDroppedNullPlaceholders"] = true;
+ b.settings_["failIfExtra"] = true;
+ CharReaderPtr reader(b.newCharReader());
Json::Value root;
Json::String errs;
- Json::CharReader* reader(b.newCharReader());
- {
- char const doc[] = "{\"a\":,\"b\":true}";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(2u, root.size());
- JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true));
- }
- {
- char const doc[] = "{\"a\":}";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(1u, root.size());
- JSONTEST_ASSERT_EQUAL(Json::nullValue, root.get("a", true));
- }
- {
- char const doc[] = "[]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(errs.empty());
- JSONTEST_ASSERT_EQUAL(0u, root.size());
- JSONTEST_ASSERT_EQUAL(Json::arrayValue, root);
- }
- {
- char const doc[] = "[null]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(errs.empty());
- JSONTEST_ASSERT_EQUAL(1u, root.size());
- }
- {
- char const doc[] = "[,]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(2u, root.size());
- }
- {
- char const doc[] = "[,,,]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(4u, root.size());
- }
- {
- char const doc[] = "[null,]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(2u, root.size());
- }
- {
- char const doc[] = "[,null]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(errs.empty());
- JSONTEST_ASSERT_EQUAL(2u, root.size());
- }
{
- char const doc[] = "[,,]";
+ char const doc[] = " true //comment1\n//comment2\r//comment3\r\n";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(3u, root.size());
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
}
{
- char const doc[] = "[null,,]";
+ char const doc[] = " true //com\rment";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(3u, root.size());
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 2, Column 1\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
}
{
- char const doc[] = "[,null,]";
+ char const doc[] = " true //com\nment";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(3u, root.size());
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL("* Line 2, Column 1\n"
+ " Extra non-whitespace after JSON value.\n",
+ errs);
+ JSONTEST_ASSERT_EQUAL(true, root.asBool());
}
- {
- char const doc[] = "[,,null]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(errs.empty());
- JSONTEST_ASSERT_EQUAL(3u, root.size());
+}
+
+struct CharReaderAllowDropNullTest : JsonTest::TestCase {
+ using Value = Json::Value;
+ using ValueCheck = std::function<void(const Value&)>;
+
+ Value nullValue = Value{Json::nullValue};
+ Value emptyArray = Value{Json::arrayValue};
+
+ ValueCheck checkEq(const Value& v) {
+ return [=](const Value& root) { JSONTEST_ASSERT_EQUAL(root, v); };
}
- {
- char const doc[] = "[[],,,]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(4u, root.size());
- JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[0u]);
+
+ static ValueCheck objGetAnd(std::string idx, ValueCheck f) {
+ return [=](const Value& root) { f(root.get(idx, true)); };
}
- {
- char const doc[] = "[,[],,]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
- JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT_STRING_EQUAL("", errs);
- JSONTEST_ASSERT_EQUAL(4u, root.size());
- JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[1u]);
+
+ static ValueCheck arrGetAnd(int idx, ValueCheck f) {
+ return [=](const Value& root) { f(root[idx]); };
}
- {
- char const doc[] = "[,,,[]]";
- bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+};
+
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowDropNullTest, issue178) {
+ struct TestSpec {
+ int line;
+ std::string doc;
+ size_t rootSize;
+ ValueCheck onRoot;
+ };
+ const TestSpec specs[] = {
+ {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))},
+ {__LINE__, R"({"a":,"b":true})", 2, objGetAnd("a", checkEq(nullValue))},
+ {__LINE__, R"({"a":})", 1, objGetAnd("a", checkEq(nullValue))},
+ {__LINE__, "[]", 0, checkEq(emptyArray)},
+ {__LINE__, "[null]", 1, nullptr},
+ {__LINE__, "[,]", 2, nullptr},
+ {__LINE__, "[,,,]", 4, nullptr},
+ {__LINE__, "[null,]", 2, nullptr},
+ {__LINE__, "[,null]", 2, nullptr},
+ {__LINE__, "[,,]", 3, nullptr},
+ {__LINE__, "[null,,]", 3, nullptr},
+ {__LINE__, "[,null,]", 3, nullptr},
+ {__LINE__, "[,,null]", 3, nullptr},
+ {__LINE__, "[[],,,]", 4, arrGetAnd(0, checkEq(emptyArray))},
+ {__LINE__, "[,[],,]", 4, arrGetAnd(1, checkEq(emptyArray))},
+ {__LINE__, "[,,,[]]", 4, arrGetAnd(3, checkEq(emptyArray))},
+ };
+ for (const auto& spec : specs) {
+ Json::CharReaderBuilder b;
+ b.settings_["allowDroppedNullPlaceholders"] = true;
+ std::unique_ptr<Json::CharReader> reader(b.newCharReader());
+
+ Json::Value root;
+ Json::String errs;
+ bool ok = reader->parse(spec.doc.data(), spec.doc.data() + spec.doc.size(),
+ &root, &errs);
JSONTEST_ASSERT(ok);
- JSONTEST_ASSERT(errs.empty());
- JSONTEST_ASSERT_EQUAL(4u, root.size());
- JSONTEST_ASSERT_EQUAL(Json::arrayValue, root[3u]);
+ JSONTEST_ASSERT_STRING_EQUAL(errs, "");
+ if (spec.onRoot) {
+ spec.onRoot(root);
+ }
}
- delete reader;
}
struct CharReaderAllowNumericKeysTest : JsonTest::TestCase {};
b.settings_["allowNumericKeys"] = true;
Json::Value root;
Json::String errs;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
char const doc[] = "{15:true,-16:true,12.01:true}";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_EQUAL(true, root.get("15", false));
JSONTEST_ASSERT_EQUAL(true, root.get("-16", false));
JSONTEST_ASSERT_EQUAL(true, root.get("12.01", false));
- delete reader;
}
struct CharReaderAllowSingleQuotesTest : JsonTest::TestCase {};
b.settings_["allowSingleQuotes"] = true;
Json::Value root;
Json::String errs;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
{
char const doc[] = "{'a':true,\"b\":true}";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
}
- delete reader;
}
struct CharReaderAllowZeroesTest : JsonTest::TestCase {};
b.settings_["allowSingleQuotes"] = true;
Json::Value root;
Json::String errs;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
{
char const doc[] = "{'a':true,\"b\":true}";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT_STRING_EQUAL("x", root["a"].asString());
JSONTEST_ASSERT_STRING_EQUAL("y", root["b"].asString());
}
- delete reader;
}
struct CharReaderAllowSpecialFloatsTest : JsonTest::TestCase {};
+JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, specialFloat) {
+ Json::CharReaderBuilder b;
+ CharReaderPtr reader(b.newCharReader());
+ Json::Value root;
+ Json::String errs;
+ {
+ char const doc[] = "{\"a\": NaN}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "* Line 1, Column 7\n"
+ " Syntax error: value, object or array expected.\n",
+ errs);
+ }
+ {
+ char const doc[] = "{\"a\": Infinity}";
+ bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT_STRING_EQUAL(
+ "* Line 1, Column 7\n"
+ " Syntax error: value, object or array expected.\n",
+ errs);
+ }
+}
+
JSONTEST_FIXTURE_LOCAL(CharReaderAllowSpecialFloatsTest, issue209) {
Json::CharReaderBuilder b;
b.settings_["allowSpecialFloats"] = true;
Json::Value root;
Json::String errs;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
{
- char const doc[] =
- "{\"a\":NaN,\"b\":Infinity,\"c\":-Infinity,\"d\":+Infinity}";
+ char const doc[] = R"({"a":NaN,"b":Infinity,"c":-Infinity,"d":+Infinity})";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
}
{
- char const doc[] = "{\"posInf\": +Infinity, \"NegInf\": -Infinity}";
+ char const doc[] = R"({"posInf": +Infinity, "NegInf": -Infinity})";
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT_STRING_EQUAL("", errs);
JSONTEST_ASSERT_EQUAL(-std::numeric_limits<double>::infinity(),
root["NegInf"].asDouble());
}
- delete reader;
}
struct EscapeSequenceTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, charReaderParseEscapeSequence) {
Json::CharReaderBuilder b;
- Json::CharReader* reader(b.newCharReader());
+ CharReaderPtr reader(b.newCharReader());
Json::Value root;
Json::String errs;
char const doc[] = "[\"\\\"\",\"\\/\",\"\\\\\",\"\\b\","
bool ok = reader->parse(doc, doc + std::strlen(doc), &root, &errs);
JSONTEST_ASSERT(ok);
JSONTEST_ASSERT(errs.empty());
- delete reader;
}
JSONTEST_FIXTURE_LOCAL(EscapeSequenceTest, writeEscapeSequence) {
}
}
+struct BomTest : JsonTest::TestCase {};
+
+JSONTEST_FIXTURE_LOCAL(BomTest, skipBom) {
+ const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}";
+ Json::Value root;
+ JSONCPP_STRING errs;
+ std::istringstream iss(with_bom);
+ bool ok = parseFromStream(Json::CharReaderBuilder(), iss, &root, &errs);
+ // The default behavior is to skip the BOM, so we can parse it normally.
+ JSONTEST_ASSERT(ok);
+ JSONTEST_ASSERT(errs.empty());
+ JSONTEST_ASSERT_STRING_EQUAL(root["key"].asString(), "value");
+}
+JSONTEST_FIXTURE_LOCAL(BomTest, notSkipBom) {
+ const std::string with_bom = "\xEF\xBB\xBF{\"key\" : \"value\"}";
+ Json::Value root;
+ JSONCPP_STRING errs;
+ std::istringstream iss(with_bom);
+ Json::CharReaderBuilder b;
+ b.settings_["skipBom"] = false;
+ bool ok = parseFromStream(b, iss, &root, &errs);
+ // Detect the BOM, and failed on it.
+ JSONTEST_ASSERT(!ok);
+ JSONTEST_ASSERT(!errs.empty());
+}
+
struct IteratorTest : JsonTest::TestCase {};
JSONTEST_FIXTURE_LOCAL(IteratorTest, convert) {
}
{
Json::Value empty;
- JSONTEST_ASSERT_EQUAL(empty.end() - empty.end(), 0);
- JSONTEST_ASSERT_EQUAL(empty.end() - empty.begin(), 0);
+ JSONTEST_ASSERT_EQUAL(0, empty.end() - empty.end());
+ JSONTEST_ASSERT_EQUAL(0, empty.end() - empty.begin());
}
}
for (; iter != value.end(); ++iter) {
out << *iter << ',';
}
- Json::String expected = "\" 9\",\"10\",\"11\",";
+ Json::String expected = R"(" 9","10","11",)";
JSONTEST_ASSERT_STRING_EQUAL(expected, out.str());
}
int main(int argc, const char* argv[]) {
JsonTest::Runner runner;
- for (auto it = local_.begin(); it != local_.end(); it++) {
- runner.add(*it);
+ for (auto& local : local_) {
+ runner.add(local);
}
return runner.runCommandLine(argc, argv);
const Json::Value jstr = "hello world";
JSONTEST_ASSERT_STRING_EQUAL(jstr.as<const char*>(), jstr.asCString());
JSONTEST_ASSERT_STRING_EQUAL(jstr.as<Json::String>(), jstr.asString());
-#ifdef JSON_USE_CPPTL
- JSONTEST_ASSERT_STRING_EQUAL(js.as<CppTL::ConstString>(), js.asConstString());
-#endif
EqEval(Json::Int(64), [](const Json::Value& j) { return j.asInt(); });
EqEval(Json::UInt(64), [](const Json::Value& j) { return j.asUInt(); });
#if defined(JSON_HAS_INT64)
--- /dev/null
+{'//this is bad JSON.'}
\ No newline at end of file
--- /dev/null
+{ "count" : 1234,, }
--- /dev/null
+.=[]
+.[0]=1
--- /dev/null
+.={}
+.count=1234
--- /dev/null
+{ "count" : 1234, }
except IOError as e:
return '<File "%s" is missing: %s>' % (path,e)
+class FailError(Exception):
+ def __init__(self, msg):
+ super(Exception, self).__init__(msg)
+
def runAllTests(jsontest_executable_path, input_dir = None,
use_valgrind=False, with_json_checker=False,
writerClass='StyledWriter'):
input_dir = os.path.join(os.getcwd(), 'data')
tests = glob(os.path.join(input_dir, '*.json'))
if with_json_checker:
- all_test_jsonchecker = glob(os.path.join(input_dir, '../jsonchecker', '*.json'))
- # These tests fail with strict json support, but pass with jsoncpp extra lieniency
- """
- Failure details:
- * Test ../jsonchecker/fail25.json
- Parsing should have failed:
- [" tab character in string "]
-
- * Test ../jsonchecker/fail13.json
- Parsing should have failed:
- {"Numbers cannot have leading zeroes": 013}
-
- * Test ../jsonchecker/fail18.json
- Parsing should have failed:
- [[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]
-
- * Test ../jsonchecker/fail8.json
- Parsing should have failed:
- ["Extra close"]]
-
- * Test ../jsonchecker/fail7.json
- Parsing should have failed:
- ["Comma after the close"],
-
- * Test ../jsonchecker/fail10.json
- Parsing should have failed:
- {"Extra value after close": true} "misplaced quoted value"
-
- * Test ../jsonchecker/fail27.json
- Parsing should have failed:
- ["line
- break"]
- """
- known_differences_withjsonchecker = [ "fail25.json", "fail13.json", "fail18.json", "fail8.json",
- "fail7.json", "fail10.json", "fail27.json" ]
- test_jsonchecker = [ test for test in all_test_jsonchecker if os.path.basename(test) not in known_differences_withjsonchecker ]
+ all_tests = glob(os.path.join(input_dir, '../jsonchecker', '*.json'))
+ # These tests fail with strict json support, but pass with JsonCPP's
+ # extra leniency features. When adding a new exclusion to this list,
+ # remember to add the test's number and reasoning here:
+ known = ["fail{}.json".format(n) for n in [
+ 4, 9, # fail because we allow trailing commas
+ 7, # fails because we allow commas after close
+ 8, # fails because we allow extra close
+ 10, # fails because we allow extra values after close
+ 13, # fails because we allow leading zeroes in numbers
+ 18, # fails because we allow deeply nested values
+ 25, # fails because we allow tab characters in strings
+ 27, # fails because we allow string line breaks
+ ]]
+ test_jsonchecker = [ test for test in all_tests
+ if os.path.basename(test) not in known]
else:
test_jsonchecker = []
+
failed_tests = []
valgrind_path = use_valgrind and VALGRIND_CMD or ''
for input_path in tests + test_jsonchecker:
print()
print('Test results: %d passed, %d failed.' % (len(tests)-len(failed_tests),
len(failed_tests)))
- return 1
+ raise FailError(repr(failed_tests))
else:
print('All %d tests passed.' % len(tests))
- return 0
def main():
from optparse import OptionParser
input_path = os.path.normpath(os.path.abspath(args[1]))
else:
input_path = None
- status = runAllTests(jsontest_executable_path, input_path,
+ runAllTests(jsontest_executable_path, input_path,
use_valgrind=options.valgrind,
with_json_checker=options.with_json_checker,
writerClass='StyledWriter')
- if status:
- sys.exit(status)
- status = runAllTests(jsontest_executable_path, input_path,
+ runAllTests(jsontest_executable_path, input_path,
use_valgrind=options.valgrind,
with_json_checker=options.with_json_checker,
writerClass='StyledStreamWriter')
- if status:
- sys.exit(status)
- status = runAllTests(jsontest_executable_path, input_path,
+ runAllTests(jsontest_executable_path, input_path,
use_valgrind=options.valgrind,
with_json_checker=options.with_json_checker,
writerClass='BuiltStyledStreamWriter')
- if status:
- sys.exit(status)
if __name__ == '__main__':
- main()
+ try:
+ main()
+ except FailError:
+ sys.exit(1)