Merge branch 'develop' into coverity_scan

This commit is contained in:
Niels 2016-07-31 14:38:52 +02:00
commit c1a5a30285
20 changed files with 1500 additions and 562 deletions

2
.gitignore vendored
View file

@ -12,3 +12,5 @@ me.nlohmann.json.docset
android android
doc/xml doc/xml
benchmarks/files/numbers/*.json

View file

@ -168,3 +168,9 @@ script:
- if [ `which valgrind` ]; then - if [ `which valgrind` ]; then
valgrind --error-exitcode=1 --leak-check=full ./json_unit ; valgrind --error-exitcode=1 --leak-check=full ./json_unit ;
fi fi
- if [ `which brew` ]; then
brew update ;
brew tap nlohmann/json ;
brew install nlohmann_json --HEAD ;
brew test nlohmann_json ;
fi

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
# define the project # define the project
project(nlohmann_json VERSION 2.0.0 LANGUAGES CXX) project(nlohmann_json VERSION 2.0.2 LANGUAGES CXX)
enable_testing() enable_testing()

View file

@ -1,9 +1,11 @@
# Change Log # Change Log
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased](https://github.com/nlohmann/json/tree/HEAD) ## [v2.0.2](https://github.com/nlohmann/json/releases/tag/v2.0.2) (2016-07-30)
[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.1...v2.0.2)
[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.1...HEAD) - value\(\) does not work with \_json\_pointer types [\#283](https://github.com/nlohmann/json/issues/283)
- Easy serialization of classes [\#280](https://github.com/nlohmann/json/issues/280)
- Build error for std::int64 [\#282](https://github.com/nlohmann/json/issues/282) - Build error for std::int64 [\#282](https://github.com/nlohmann/json/issues/282)

View file

@ -10,6 +10,7 @@ all: json_unit
# clean up # clean up
clean: clean:
rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM rm -fr json_unit json_benchmarks fuzz fuzz-testing *.dSYM
rm -fr benchmarks/files/numbers/*.json
$(MAKE) clean -Cdoc $(MAKE) clean -Cdoc
@ -85,6 +86,7 @@ pretty:
# benchmarks # benchmarks
json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/cxxopts.hpp src/json.hpp
cd benchmarks/files/numbers ; python generate.py
$(CXX) -std=c++11 $(CXXFLAGS) -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@ $(CXX) -std=c++11 $(CXXFLAGS) -O3 -flto -I src -I benchmarks $< $(LDFLAGS) -o $@
./json_benchmarks ./json_benchmarks
@ -93,7 +95,9 @@ json_benchmarks: benchmarks/benchmarks.cpp benchmarks/benchpress.hpp benchmarks/
# changelog # changelog
########################################################################## ##########################################################################
NEXT_VERSION ?= "unreleased"
ChangeLog.md: ChangeLog.md:
github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s github_changelog_generator -o ChangeLog.md --simple-list --release-url https://github.com/nlohmann/json/releases/tag/%s --future-release $(NEXT_VERSION)
gsed -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md gsed -i 's|https://github.com/nlohmann/json/releases/tag/HEAD|https://github.com/nlohmann/json/tree/HEAD|' ChangeLog.md
gsed -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md gsed -i '2i All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).' ChangeLog.md

View file

@ -4,7 +4,7 @@
[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk?svg=true)](https://ci.appveyor.com/project/nlohmann/json) [![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk?svg=true)](https://ci.appveyor.com/project/nlohmann/json)
[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/wuiuqYiYqRTdI3rG) [![Try online](https://img.shields.io/badge/try-online-blue.svg)](http://melpon.org/wandbox/permlink/p5o4znPnGHJpDVqN)
[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
[![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) [![Github Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases)
@ -24,7 +24,7 @@ Other aspects were not so important to us:
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. - **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) with a decent regular expression processor should be even faster (but would consist of more files which makes the integration harder). - **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) may be even faster (but would consist of more files which makes the integration harder).
See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information.
@ -505,7 +505,7 @@ $ make
$ ./json_unit "*" $ ./json_unit "*"
=============================================================================== ===============================================================================
All tests passed (5568718 assertions in 32 test cases) All tests passed (8905012 assertions in 32 test cases)
``` ```
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).

View file

@ -44,6 +44,36 @@ BENCHMARK("parse twitter.json", [](benchpress::context* ctx)
} }
}) })
BENCHMARK("parse numbers/floats.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/numbers/floats.json");
nlohmann::json j;
j << input_file;
}
})
BENCHMARK("parse numbers/signed_ints.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/numbers/signed_ints.json");
nlohmann::json j;
j << input_file;
}
})
BENCHMARK("parse numbers/unsigned_ints.json", [](benchpress::context* ctx)
{
for (size_t i = 0; i < ctx->num_iterations(); ++i)
{
std::ifstream input_file("benchmarks/files/numbers/unsigned_ints.json");
nlohmann::json j;
j << input_file;
}
})
BENCHMARK("dump jeopardy.json", [](benchpress::context* ctx) BENCHMARK("dump jeopardy.json", [](benchpress::context* ctx)
{ {
std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json"); std::ifstream input_file("benchmarks/files/jeopardy/jeopardy.json");

View file

@ -0,0 +1,25 @@
#!/usr/bin/env python
import json
import random
import sys
random.seed(0)
# floats
result_floats = []
for x in range(0, 1000000):
result_floats.append(random.uniform(-100000000.0, 100000000.0))
json.dump(result_floats, open("floats.json", "w"), indent=2)
# unsigned integers
result_uints = []
for x in range(0, 1000000):
result_uints.append(random.randint(0, 18446744073709551615))
json.dump(result_uints, open("unsigned_ints.json", "w"), indent=2)
# signed integers
result_sints = []
for x in range(0, 1000000):
result_sints.append(random.randint(-9223372036854775808, 9223372036854775807))
json.dump(result_sints, open("signed_ints.json", "w"), indent=2)

View file

@ -5,7 +5,7 @@
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "JSON for Modern C++" PROJECT_NAME = "JSON for Modern C++"
PROJECT_NUMBER = 2.0.0 PROJECT_NUMBER = 2.0.2
PROJECT_BRIEF = PROJECT_BRIEF =
PROJECT_LOGO = PROJECT_LOGO =
OUTPUT_DIRECTORY = . OUTPUT_DIRECTORY = .

View file

@ -1 +1 @@
<a target="_blank" href="http://melpon.org/wandbox/permlink/k5KRwVJ42VggxxzX"><b>online</b></a> <a target="_blank" href="http://melpon.org/wandbox/permlink/p5o4znPnGHJpDVqN"><b>online</b></a>

View file

@ -0,0 +1,29 @@
#include <json.hpp>
using json = nlohmann::json;
int main()
{
// create a JSON object with different entry types
json j =
{
{"integer", 1},
{"floating", 42.23},
{"string", "hello world"},
{"boolean", true},
{"object", {{"key1", 1}, {"key2", 2}}},
{"array", {1, 2, 3}}
};
// access existing values
int v_integer = j.value("/integer"_json_pointer, 0);
double v_floating = j.value("/floating"_json_pointer, 47.11);
// access nonexisting values and rely on default value
std::string v_string = j.value("/nonexisting"_json_pointer, "oops");
bool v_boolean = j.value("/nonexisting"_json_pointer, false);
// output values
std::cout << std::boolalpha << v_integer << " " << v_floating
<< " " << v_string << " " << v_boolean << "\n";
}

View file

@ -0,0 +1 @@
<a target="_blank" href="http://melpon.org/wandbox/permlink/K4L4D6nibuGXbjfd"><b>online</b></a>

View file

@ -0,0 +1 @@
1 42.23 oops false

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View file

@ -268,4 +268,4 @@ The container functions known from STL have been extended to support the differe
@author [Niels Lohmann](http://nlohmann.me) @author [Niels Lohmann](http://nlohmann.me)
@see https://github.com/nlohmann/json to download the source code @see https://github.com/nlohmann/json to download the source code
@version 2.0.0 @version 2.0.2

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 KiB

After

Width:  |  Height:  |  Size: 440 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (fuzz test support) __| | __| | | | JSON for Modern C++ (fuzz test support)
| | |__ | | | | | | version 2.0.0 | | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Run "make fuzz_testing" and follow the instructions. Run "make fuzz_testing" and follow the instructions.

View file

@ -1,7 +1,7 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite) __| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 2.0.1 | | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@ -3767,6 +3767,8 @@ TEST_CASE("element access")
} }
SECTION("access specified element with default value") SECTION("access specified element with default value")
{
SECTION("given a key")
{ {
SECTION("access existing value") SECTION("access existing value")
{ {
@ -3889,6 +3891,135 @@ TEST_CASE("element access")
} }
} }
SECTION("given a JSON pointer")
{
SECTION("access existing value")
{
CHECK(j.value("/integer"_json_pointer, 2) == 1);
CHECK(j.value("/integer"_json_pointer, 1.0) == Approx(1));
CHECK(j.value("/unsigned"_json_pointer, 2) == 1u);
CHECK(j.value("/unsigned"_json_pointer, 1.0) == Approx(1u));
CHECK(j.value("/null"_json_pointer, json(1)) == json());
CHECK(j.value("/boolean"_json_pointer, false) == true);
CHECK(j.value("/string"_json_pointer, "bar") == "hello world");
CHECK(j.value("/string"_json_pointer, std::string("bar")) == "hello world");
CHECK(j.value("/floating"_json_pointer, 12.34) == Approx(42.23));
CHECK(j.value("/floating"_json_pointer, 12) == 42);
CHECK(j.value("/object"_json_pointer, json({{"foo", "bar"}})) == json(json::object()));
CHECK(j.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
CHECK(j_const.value("/integer"_json_pointer, 2) == 1);
CHECK(j_const.value("/integer"_json_pointer, 1.0) == Approx(1));
CHECK(j_const.value("/unsigned"_json_pointer, 2) == 1u);
CHECK(j_const.value("/unsigned"_json_pointer, 1.0) == Approx(1u));
CHECK(j_const.value("/boolean"_json_pointer, false) == true);
CHECK(j_const.value("/string"_json_pointer, "bar") == "hello world");
CHECK(j_const.value("/string"_json_pointer, std::string("bar")) == "hello world");
CHECK(j_const.value("/floating"_json_pointer, 12.34) == Approx(42.23));
CHECK(j_const.value("/floating"_json_pointer, 12) == 42);
CHECK(j_const.value("/object"_json_pointer, json({{"foo", "bar"}})) == json(json::object()));
CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3}));
}
SECTION("access non-existing value")
{
CHECK(j.value("/not/existing"_json_pointer, 2) == 2);
CHECK(j.value("/not/existing"_json_pointer, 2u) == 2u);
CHECK(j.value("/not/existing"_json_pointer, false) == false);
CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar");
CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2);
CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u);
CHECK(j_const.value("/not/existing"_json_pointer, false) == false);
CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar");
CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34));
CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}}));
CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100}));
}
SECTION("access on non-object type")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with null");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), "cannot use value() with null");
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with boolean");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with boolean");
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with string");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with string");
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with array");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1), "cannot use value() with array");
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with number");
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with number");
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK_THROWS_AS(j_nonobject.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_AS(j_nonobject_const.value("/foo"_json_pointer, 1), std::domain_error);
CHECK_THROWS_WITH(j_nonobject.value("/foo"_json_pointer, 1), "cannot use value() with number");
CHECK_THROWS_WITH(j_nonobject_const.value("/foo"_json_pointer, 1),
"cannot use value() with number");
}
}
}
}
SECTION("front and back") SECTION("front and back")
{ {
// "array" is the smallest key // "array" is the smallest key
@ -9716,6 +9847,39 @@ TEST_CASE("parser class")
CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'"); CHECK_THROWS_WITH(json::parser("\"\b\"").parse(), "parse error - unexpected '\"'");
// improve code coverage // improve code coverage
CHECK_THROWS_AS(json::parser("\uFF01").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("\uFF01").parse(), std::invalid_argument);
// unescaped control characters
CHECK_THROWS_AS(json::parser("\"\x00\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x01\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x02\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x03\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x04\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x05\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x06\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x07\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x08\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x09\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0a\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0b\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0c\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0d\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0e\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x0f\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x10\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x11\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x12\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x13\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x14\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x15\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x16\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x17\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x18\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x19\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1a\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1b\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1c\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1d\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1e\"").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("\"\x1f\"").parse(), std::invalid_argument);
} }
SECTION("escaped") SECTION("escaped")
@ -10326,6 +10490,14 @@ TEST_CASE("parser class")
CHECK(j_empty_array == json()); CHECK(j_empty_array == json());
} }
} }
SECTION("copy constructor")
{
json::string_t* s = new json::string_t("[1,2,3,4]");
json::parser p(*s);
delete s;
CHECK(p.parse() == json({1, 2, 3, 4}));
}
} }
TEST_CASE("README", "[hide]") TEST_CASE("README", "[hide]")
@ -12113,19 +12285,23 @@ TEST_CASE("RFC 7159 examples")
TEST_CASE("Unicode", "[hide]") TEST_CASE("Unicode", "[hide]")
{ {
SECTION("full enumeration of Unicode codepoints") SECTION("full enumeration of Unicode code points")
{ {
// create a string from a codepoint // create an escaped string from a code point
auto codepoint_to_unicode = [](std::size_t cp) const auto codepoint_to_unicode = [](std::size_t cp)
{ {
char* buffer = new char[10]; // copd points are represented as a six-character sequence: a
sprintf(buffer, "\\u%04lx", cp); // reverse solidus, followed by the lowercase letter u, followed
std::string result(buffer); // by four hexadecimal digits that encode the character's code
delete[] buffer; // point
return result; std::stringstream ss;
ss << "\\u" << std::setw(4) << std::setfill('0') << std::hex << cp;
return ss.str();
}; };
// generate all codepoints // generate all UTF-8 code points; in total, 1112064 code points are
// generated: 0x1FFFFF code points - 2048 invalid values between
// 0xD800 and 0xDFFF.
for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp) for (std::size_t cp = 0; cp <= 0x10FFFFu; ++cp)
{ {
// The Unicode standard permanently reserves these code point // The Unicode standard permanently reserves these code point
@ -12135,34 +12311,57 @@ TEST_CASE("Unicode", "[hide]")
// no UTF forms, including UTF-16, can encode these code points. // no UTF forms, including UTF-16, can encode these code points.
if (cp >= 0xD800u and cp <= 0xDFFFu) if (cp >= 0xD800u and cp <= 0xDFFFu)
{ {
// if we would not skip these code points, we would get a
// "missing low surrogate" exception
continue; continue;
} }
std::string res; // string to store the code point as in \uxxxx format
std::string escaped_string;
// string to store the code point as unescaped character sequence
std::string unescaped_string;
if (cp < 0x10000u) if (cp < 0x10000u)
{ {
// codepoint can be represented with 16 bit // code points in the Basic Multilingual Plane can be
res += codepoint_to_unicode(cp); // represented with one \\uxxxx sequence
escaped_string = codepoint_to_unicode(cp);
// All Unicode characters may be placed within the quotation
// marks, except for the characters that must be escaped:
// quotation mark, reverse solidus, and the control characters
// (U+0000 through U+001F); we ignore these code points as
// they are checked with codepoint_to_unicode.
if (cp > 0x1f and cp != 0x22 and cp != 0x5c)
{
unescaped_string = json::lexer::to_unicode(cp);
}
} }
else else
{ {
// codepoint can be represented with a pair // To escape an extended character that is not in the Basic
res += codepoint_to_unicode(0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu)); // Multilingual Plane, the character is represented as a
res += codepoint_to_unicode(0xdc00u + ((cp - 0x10000u) & 0x3ffu)); // 12-character sequence, encoding the UTF-16 surrogate pair
const auto codepoint1 = 0xd800u + (((cp - 0x10000u) >> 10) & 0x3ffu);
const auto codepoint2 = 0xdc00u + ((cp - 0x10000u) & 0x3ffu);
escaped_string = codepoint_to_unicode(codepoint1);
escaped_string += codepoint_to_unicode(codepoint2);
unescaped_string += json::lexer::to_unicode(codepoint1, codepoint2);
} }
try // all other code points are valid and must not yield parse errors
{ CAPTURE(cp);
json j1, j2; CAPTURE(escaped_string);
CHECK_NOTHROW(j1 = json::parse("\"" + res + "\"")); CAPTURE(unescaped_string);
json j1, j2, j3, j4;
CHECK_NOTHROW(j1 = json::parse("\"" + escaped_string + "\""));
CHECK_NOTHROW(j2 = json::parse(j1.dump())); CHECK_NOTHROW(j2 = json::parse(j1.dump()));
CHECK(j1 == j2); CHECK(j1 == j2);
}
catch (std::invalid_argument) CHECK_NOTHROW(j3 = json::parse("\"" + unescaped_string + "\""));
{ CHECK_NOTHROW(j4 = json::parse(j3.dump()));
// we ignore parsing errors CHECK(j3 == j4);
}
} }
} }
@ -12175,6 +12374,8 @@ TEST_CASE("Unicode", "[hide]")
CHECK_NOTHROW(j << f); CHECK_NOTHROW(j << f);
// the array has 1112064 + 1 elemnts (a terminating "null" value) // the array has 1112064 + 1 elemnts (a terminating "null" value)
// Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between
// 0xD800 and 0xDFFF.
CHECK(j.size() == 1112065); CHECK(j.size() == 1112065);
SECTION("check JSON Pointers") SECTION("check JSON Pointers")
@ -14159,6 +14360,19 @@ TEST_CASE("regression tests")
// check roundtrip // check roundtrip
CHECK(doc.patch(json::diff(doc, expected)) == expected); CHECK(doc.patch(json::diff(doc, expected)) == expected);
} }
SECTION("issue #283 - value() does not work with _json_pointer types")
{
json j =
{
{"object", {{"key1", 1}, {"key2", 2}}},
};
int at_integer = j.at("/object/key2"_json_pointer);
int val_integer = j.value("/object/key2"_json_pointer, 0);
CHECK(at_integer == val_integer);
}
} }
// special test case to check if memory is leaked if constructor throws // special test case to check if memory is leaked if constructor throws