添加依赖库

This commit is contained in:
kerwincui
2021-07-09 21:37:19 +08:00
parent 1e4fc7ae4e
commit 7fb709c31f
410 changed files with 44833 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
check_required_components("@PROJECT_NAME@")

View File

@@ -0,0 +1,100 @@
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
add_compile_options(
-pedantic
-Wall
-Wcast-align
-Wcast-qual
-Wconversion
-Wctor-dtor-privacy
-Wdisabled-optimization
-Werror
-Wextra
-Wformat=2
-Winit-self
-Wmissing-include-dirs
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wparentheses
-Wredundant-decls
-Wshadow
-Wsign-promo
-Wstrict-aliasing
-Wundef
)
if(NOT MINGW)
add_compile_options(
-std=c++98
)
endif()
if(${COVERAGE})
set(CMAKE_CXX_FLAGS "-fprofile-arcs -ftest-coverage")
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8) AND (NOT ${COVERAGE}))
add_compile_options(-g -Og)
else()
add_compile_options(-g -O0)
endif()
add_compile_options(
-Wstrict-null-sentinel
-Wno-vla # Allow VLA in tests
)
add_definitions(-DHAS_VARIABLE_LENGTH_ARRAY)
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.5)
add_compile_options(-Wlogical-op) # the flag exists in 4.4 but is buggy
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6)
add_compile_options(-Wnoexcept)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(
-Wc++11-compat
-Wdeprecated-register
-Wno-vla-extension # Allow VLA in tests
)
add_definitions(
-DHAS_VARIABLE_LENGTH_ARRAY
-DSUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR
)
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0) AND (NOT ${COVERAGE}))
add_compile_options(-g -Og)
else()
add_compile_options(-g -O0)
endif()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0) AND (NOT ${COVERAGE}))
add_compile_options(-g -Og)
else()
add_compile_options(-g -O0)
endif()
endif()
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_compile_options(
/W4 # Set warning level
/WX # Treats all compiler warnings as errors.
)
if (NOT MSVC_VERSION LESS 1910) # >= Visual Studio 2017
add_compile_options(
/Zc:__cplusplus # Enable updated __cplusplus macro
)
endif()
endif()

View File

@@ -0,0 +1,20 @@
#!/bin/bash -eux
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16
sleep 3
export DISPLAY=:1.0
mkdir -p /tmp/arduino
curl -sS http://downloads.arduino.cc/arduino-$VERSION-linux64.tar.xz | tar xJ -C /tmp/arduino --strip 1 ||
curl -sS http://downloads.arduino.cc/arduino-$VERSION-linux64.tgz | tar xz -C /tmp/arduino --strip 1
export PATH=$PATH:/tmp/arduino/
if [[ "$BOARD" =~ "arduino:samd:" ]]; then
arduino --install-boards arduino:samd
fi
ln -s $PWD /tmp/arduino/libraries/ArduinoJson
for EXAMPLE in $PWD/examples/*/*.ino; do
arduino --verify --board $BOARD $EXAMPLE
done

View File

@@ -0,0 +1,10 @@
#!/bin/sh -ex
BOARD=$1
cd "$(dirname "$0")/../../"
cp extras/particle/src/smocktest.ino src/
cp extras/particle/project.properties ./
particle compile "$BOARD"

View File

@@ -0,0 +1,20 @@
#!/bin/sh -eux
BOARD=$1
case $BOARD in
uno)
platformio lib install 868 # SD library
platformio lib install 872 # Ethernet library
;;
esp01)
platformio lib uninstall 161 || true
platformio lib uninstall 868 || true
platformio lib uninstall 872 || true
;;
esac
for EXAMPLE in $PWD/examples/*/*.ino;
do
platformio ci $EXAMPLE -l '.' -b $BOARD
done

View File

@@ -0,0 +1,59 @@
# ArduinoJson - https://arduinojson.org
# Copyright Benoit Blanchon 2014-2021
# MIT License
if(MSVC)
add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
endif()
add_executable(msgpack_reproducer
msgpack_fuzzer.cpp
reproducer.cpp
)
target_link_libraries(msgpack_reproducer
ArduinoJson
)
add_executable(json_reproducer
json_fuzzer.cpp
reproducer.cpp
)
target_link_libraries(json_reproducer
ArduinoJson
)
macro(add_fuzzer name)
set(FUZZER "${name}_fuzzer")
set(CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_corpus")
set(SEED_CORPUS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${name}_seed_corpus")
add_executable("${FUZZER}"
"${name}_fuzzer.cpp"
)
target_link_libraries("${FUZZER}"
ArduinoJson
)
set_target_properties("${FUZZER}"
PROPERTIES
COMPILE_FLAGS
"-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all"
LINK_FLAGS
"-fprofile-instr-generate -fcoverage-mapping -fsanitize=fuzzer -fno-sanitize-recover=all"
)
add_test(
NAME
"${FUZZER}"
COMMAND
"${FUZZER}" "${CORPUS_DIR}" "${SEED_CORPUS_DIR}" -max_total_time=5 -timeout=1
)
set_tests_properties("${FUZZER}"
PROPERTIES
LABELS "Fuzzing"
)
endmacro()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6)
add_fuzzer(json)
add_fuzzer(msgpack)
endif()

View File

@@ -0,0 +1,22 @@
# CAUTION: this file is invoked by https://github.com/google/oss-fuzz
CXXFLAGS += -I../../src -DARDUINOJSON_DEBUG=1
all: \
$(OUT)/json_fuzzer \
$(OUT)/json_fuzzer_seed_corpus.zip \
$(OUT)/json_fuzzer.options \
$(OUT)/msgpack_fuzzer \
$(OUT)/msgpack_fuzzer_seed_corpus.zip \
$(OUT)/msgpack_fuzzer.options
$(OUT)/%_fuzzer: %_fuzzer.cpp $(shell find ../../src -type f)
$(CXX) $(CXXFLAGS) $< -o$@ $(LIB_FUZZING_ENGINE)
$(OUT)/%_fuzzer_seed_corpus.zip: %_seed_corpus/*
zip -j $@ $?
$(OUT)/%_fuzzer.options:
@echo "[libfuzzer]" > $@
@echo "max_len = 256" >> $@
@echo "timeout = 10" >> $@

View File

@@ -0,0 +1,11 @@
#include <ArduinoJson.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
DynamicJsonDocument doc(4096);
DeserializationError error = deserializeJson(doc, data, size);
if (!error) {
std::string json;
serializeJson(doc, json);
}
return 0;
}

View File

@@ -0,0 +1,10 @@
//comment
/*comment*/
[ //comment
/*comment*/"comment"/*comment*/,//comment
/*comment*/{//comment
/* comment*/"key"//comment
: //comment
"value"//comment
}/*comment*/
]//comment

View File

@@ -0,0 +1 @@
[1,[2,[3,[4,[5,[6,[7,[8,[9,[10,[11,[12,[13,[14,[15,[16,[17,[18,[19,[20,[21,[22,[23,[24,[25,[26,[27,[28,[29,[30,[31,[32,[33,[34,[35,[36,[37,[38,[39,[40,[41,[42,[43,[44,[45,[46,[47,[48,[49,[50,[51,[52,[53,[54,[55,[56,[57,[58,[59,[60,[61,[62,[63,[64,[65,[66,[67,[68,[69,[70,[71,[72,[73,[74,[75,[76,[77,[78,[79,[80,[81,[82,[83,[84,[85,[86,[87,[88,[89,[90,[91,[92,[93,[94,[95,[96,[97,[98,[99,[100,[101,[102,[103,[104,[105,[106,[107,[108,[109,[110,[111,[112,[113,[114,[115,[116,[117,[118,[119,[120]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]

View File

@@ -0,0 +1,24 @@
[
123,
-123,
123.456,
-123.456,
12e34,
12e-34,
12e+34,
12E34,
12E-34,
12E+34,
12.34e56,
12.34e-56,
12.34e+56,
12.34E56,
12.34E-56,
12.34E+56,
NaN,
-NaN,
+NaN,
Infinity,
+Infinity,
-Infinity
]

View File

@@ -0,0 +1,53 @@
{
"coord": {
"lon": -0.13,
"lat": 51.51
},
"weather": [
{
"id": 301,
"main": "Drizzle",
"description": "drizzle",
"icon": "09n"
},
{
"id": 701,
"main": "Mist",
"description": "mist",
"icon": "50n"
},
{
"id": 741,
"main": "Fog",
"description": "fog",
"icon": "50n"
}
],
"base": "stations",
"main": {
"temp": 281.87,
"pressure": 1032,
"humidity": 100,
"temp_min": 281.15,
"temp_max": 283.15
},
"visibility": 2900,
"wind": {
"speed": 1.5
},
"clouds": {
"all": 90
},
"dt": 1483820400,
"sys": {
"type": 1,
"id": 5091,
"message": 0.0226,
"country": "GB",
"sunrise": 1483776245,
"sunset": 1483805443
},
"id": 2643743,
"name": "London",
"cod": 200
}

View File

@@ -0,0 +1,8 @@
[
"hello",
'hello',
hello,
{"hello":"world"},
{'hello':'world'},
{hello:world}
]

View File

@@ -0,0 +1,90 @@
{
"response": {
"version": "0.1",
"termsofService": "http://www.wunderground.com/weather/api/d/terms.html",
"features": {
"conditions": 1
}
},
"current_observation": {
"image": {
"url": "http://icons-ak.wxug.com/graphics/wu2/logo_130x80.png",
"title": "Weather Underground",
"link": "http://www.wunderground.com"
},
"display_location": {
"full": "San Francisco, CA",
"city": "San Francisco",
"state": "CA",
"state_name": "California",
"country": "US",
"country_iso3166": "US",
"zip": "94101",
"latitude": "37.77500916",
"longitude": "-122.41825867",
"elevation": "47.00000000"
},
"observation_location": {
"full": "SOMA - Near Van Ness, San Francisco, California",
"city": "SOMA - Near Van Ness, San Francisco",
"state": "California",
"country": "US",
"country_iso3166": "US",
"latitude": "37.773285",
"longitude": "-122.417725",
"elevation": "49 ft"
},
"estimated": {},
"station_id": "KCASANFR58",
"observation_time": "Last Updated on June 27, 5:27 PM PDT",
"observation_time_rfc822": "Wed, 27 Jun 2012 17:27:13 -0700",
"observation_epoch": "1340843233",
"local_time_rfc822": "Wed, 27 Jun 2012 17:27:14 -0700",
"local_epoch": "1340843234",
"local_tz_short": "PDT",
"local_tz_long": "America/Los_Angeles",
"local_tz_offset": "-0700",
"weather": "Partly Cloudy",
"temperature_string": "66.3 F (19.1 C)",
"temp_f": 66.3,
"temp_c": 19.1,
"relative_humidity": "65%",
"wind_string": "From the NNW at 22.0 MPH Gusting to 28.0 MPH",
"wind_dir": "NNW",
"wind_degrees": 346,
"wind_mph": 22,
"wind_gust_mph": "28.0",
"wind_kph": 35.4,
"wind_gust_kph": "45.1",
"pressure_mb": "1013",
"pressure_in": "29.93",
"pressure_trend": "+",
"dewpoint_string": "54 F (12 C)",
"dewpoint_f": 54,
"dewpoint_c": 12,
"heat_index_string": "NA",
"heat_index_f": "NA",
"heat_index_c": "NA",
"windchill_string": "NA",
"windchill_f": "NA",
"windchill_c": "NA",
"feelslike_string": "66.3 F (19.1 C)",
"feelslike_f": "66.3",
"feelslike_c": "19.1",
"visibility_mi": "10.0",
"visibility_km": "16.1",
"solarradiation": "",
"UV": "5",
"precip_1hr_string": "0.00 in ( 0 mm)",
"precip_1hr_in": "0.00",
"precip_1hr_metric": " 0",
"precip_today_string": "0.00 in (0 mm)",
"precip_today_in": "0.00",
"precip_today_metric": "0",
"icon": "partlycloudy",
"icon_url": "http://icons-ak.wxug.com/i/c/k/partlycloudy.gif",
"forecast_url": "http://www.wunderground.com/US/CA/San_Francisco.html",
"history_url": "http://www.wunderground.com/history/airport/KCASANFR58/2012/6/27/DailyHistory.html",
"ob_url": "http://www.wunderground.com/cgi-bin/findweather/getForecast?query=37.773285,-122.417725"
}
}

View File

@@ -0,0 +1,11 @@
#include <ArduinoJson.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
DynamicJsonDocument doc(4096);
DeserializationError error = deserializeMsgPack(doc, data, size);
if (!error) {
std::string json;
serializeMsgPack(doc, json);
}
return 0;
}

View File

@@ -0,0 +1 @@
<EFBFBD><EFBFBD>hello<EFBFBD>world

View File

@@ -0,0 +1 @@
<EFBFBD><EFBFBD>one<01>two

View File

@@ -0,0 +1 @@
<EFBFBD>@ !<21><><EFBFBD>o

View File

@@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD>

View File

@@ -0,0 +1 @@
<EFBFBD>4Vx<56><78><EFBFBD><EFBFBD>

View File

@@ -0,0 +1 @@
<EFBFBD>4Vx<56><78><EFBFBD><EFBFBD>

View File

@@ -0,0 +1,50 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
// This file is NOT use by Google's OSS fuzz
// I only use it to reproduce the bugs found
#include <stdint.h> // size_t
#include <stdio.h> // fopen et al.
#include <stdlib.h> // exit
#include <iostream>
#include <vector>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
std::vector<uint8_t> read(const char* path) {
FILE* f = fopen(path, "rb");
if (!f) {
std::cerr << "Failed to open " << path << std::endl;
exit(1);
}
fseek(f, 0, SEEK_END);
size_t size = static_cast<size_t>(ftell(f));
fseek(f, 0, SEEK_SET);
std::vector<uint8_t> buffer(size);
if (fread(buffer.data(), 1, size, f) != size) {
fclose(f);
std::cerr << "Failed to read " << path << std::endl;
exit(1);
}
fclose(f);
return buffer;
}
int main(int argc, const char* argv[]) {
if (argc < 2) {
std::cerr << "Usage: msgpack_fuzzer files" << std::endl;
return 1;
}
for (int i = 1; i < argc; i++) {
std::cout << "Loading " << argv[i] << std::endl;
std::vector<uint8_t> buffer = read(argv[i]);
LLVMFuzzerTestOneInput(buffer.data(), buffer.size());
}
return 0;
}

View File

@@ -0,0 +1 @@
name=ArduinoJsonCI

View File

@@ -0,0 +1,5 @@
#include "ArduinoJson.h"
void setup() {}
void loop() {}

View File

@@ -0,0 +1,21 @@
#!/bin/bash
TAG=$(git describe)
OUTPUT="ArduinoJson-$TAG.zip"
cd $(dirname $0)/../../..
# remove existing file
rm -f $OUTPUT
# create zip
7z a $OUTPUT \
-xr!.vs \
ArduinoJson/CHANGELOG.md \
ArduinoJson/examples \
ArduinoJson/src \
ArduinoJson/keywords.txt \
ArduinoJson/library.properties \
ArduinoJson/LICENSE.md \
ArduinoJson/README.md \
ArduinoJson/ArduinoJson.h

View File

@@ -0,0 +1,82 @@
#!/bin/bash
set -e
TAG=$(git describe)
RE_RELATIVE_INCLUDE='^#include[[:space:]]*"(.*)"'
RE_ABSOLUTE_INCLUDE='^#include[[:space:]]*<(ArduinoJson/.*)>'
RE_SYSTEM_INCLUDE='^#include[[:space:]]*<(.*)>'
RE_EMPTY='^(#pragma[[:space:]]+once)?[[:space:]]*(//.*)?$'
SRC_DIRECTORY="$(realpath "$(dirname $0)/../../src")"
declare -A INCLUDED
process()
{
local PARENT=$1
local FOLDER=$(dirname $1)
local SHOW_COMMENT=$2
while IFS= read -r LINE; do
if [[ $LINE =~ $RE_ABSOLUTE_INCLUDE ]]; then
local CHILD=${BASH_REMATCH[1]}
local CHILD_PATH
CHILD_PATH=$(realpath "$SRC_DIRECTORY/$CHILD")
echo "$PARENT -> $CHILD" >&2
if [[ ! ${INCLUDED[$CHILD_PATH]} ]]; then
INCLUDED[$CHILD_PATH]=true
process "$CHILD" false
fi
elif [[ $LINE =~ $RE_RELATIVE_INCLUDE ]]; then
local CHILD=${BASH_REMATCH[1]}
pushd "$FOLDER" > /dev/null
local CHILD_PATH
CHILD_PATH=$(realpath "$CHILD")
echo "$PARENT -> $CHILD" >&2
if [[ ! ${INCLUDED[$CHILD_PATH]} ]]; then
INCLUDED[$CHILD_PATH]=true
process "$CHILD" false
fi
popd > /dev/null
elif [[ $LINE =~ $RE_SYSTEM_INCLUDE ]]; then
local CHILD=${BASH_REMATCH[1]}
echo "$PARENT -> <$CHILD>" >&2
if [[ ! ${INCLUDED[$CHILD]} ]]; then
echo "#include <$CHILD>"
INCLUDED[$CHILD]=true
fi
elif [[ "${SHOW_COMMENT}" = "true" ]] ; then
echo "$LINE"
elif [[ ! $LINE =~ $RE_EMPTY ]]; then
echo "$LINE"
fi
done < $PARENT
}
simplify_namespaces() {
perl -p0i -e 's|\} // namespace ARDUINOJSON_NAMESPACE\r?\nnamespace ARDUINOJSON_NAMESPACE \{\r?\n||igs' "$1"
rm -f "$1.bak"
}
cd $(dirname $0)/../..
INCLUDED=()
process src/ArduinoJson.h true > ../ArduinoJson-$TAG.h
simplify_namespaces ../ArduinoJson-$TAG.h
g++ -x c++ -c -o ../smoketest.o - <<END
#include "../ArduinoJson-$TAG.h"
int main() {
StaticJsonDocument<300> doc;
deserializeJson(doc, "{}");
}
END
INCLUDED=()
process src/ArduinoJson.hpp true > ../ArduinoJson-$TAG.hpp
simplify_namespaces ../ArduinoJson-$TAG.hpp
g++ -x c++ -c -o ../smoketest.o - <<END
#include "../ArduinoJson-$TAG.hpp"
int main() {
ArduinoJson::StaticJsonDocument<300> doc;
ArduinoJson::deserializeJson(doc, "{}");
}
END

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eu
SOURCE_DIR="$(dirname "$0")/../.."
WORK_DIR=$(mktemp -d)
trap 'rm -rf "$WORK_DIR"' EXIT
cp "$SOURCE_DIR/README.md" "$WORK_DIR/README.md"
cp "$SOURCE_DIR/CHANGELOG.md" "$WORK_DIR/CHANGELOG.md"
cp "$SOURCE_DIR/library.properties" "$WORK_DIR/library.properties"
cp "$SOURCE_DIR/LICENSE.md" "$WORK_DIR/LICENSE.txt"
cp -r "$SOURCE_DIR/src" "$WORK_DIR/"
cp -r "$SOURCE_DIR/examples" "$WORK_DIR/"
cd "$WORK_DIR"
particle library upload
particle library publish

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env bash
set -eu
cd "$(dirname "$0")/../.."
VERSION="$1"
DATE=$(date +%F)
TAG="v$VERSION"
VERSION_REGEX="[0-9a-z\\.\\-]+"
update_version_in_source () {
IFS=".-" read MAJOR MINOR REVISION EXTRA < <(echo "$VERSION")
UNDERLINE=$(printf -- '-%.0s' $(seq 1 ${#TAG}))
sed -i~ -bE "s/version=$VERSION_REGEX/version=$VERSION/; s|ardu-badge.com/ArduinoJson/$VERSION_REGEX|ardu-badge.com/ArduinoJson/$VERSION|; " README.md
rm README.md~
sed -i~ -bE "4s/HEAD/$TAG ($DATE)/; 5s/-+/$UNDERLINE/" CHANGELOG.md
rm CHANGELOG.md~
sed -i~ -bE "s/(project\\s*\\(ArduinoJson\\s+VERSION\\s+).*?\\)/\\1$MAJOR.$MINOR.$REVISION)/" CMakeLists.txt
rm CMakeLists.txt~
sed -i~ -bE "s/\"version\":.*$/\"version\": \"$VERSION\",/" library.json
rm library.json~
sed -i~ -bE "s/version=.*$/version=$VERSION/" library.properties
rm library.properties~
sed -i~ -bE "s/version: .*$/version: $VERSION.{build}/" appveyor.yml
rm appveyor.yml~
sed -i~ -bE \
-e "s/ARDUINOJSON_VERSION .*$/ARDUINOJSON_VERSION \"$VERSION\"/" \
-e "s/ARDUINOJSON_VERSION_MAJOR .*$/ARDUINOJSON_VERSION_MAJOR $MAJOR/" \
-e "s/ARDUINOJSON_VERSION_MINOR .*$/ARDUINOJSON_VERSION_MINOR $MINOR/" \
-e "s/ARDUINOJSON_VERSION_REVISION .*$/ARDUINOJSON_VERSION_REVISION $REVISION/" \
src/ArduinoJson/version.hpp
rm src/ArduinoJson/version.hpp*~
}
commit_new_version () {
git add src/ArduinoJson/version.hpp README.md CHANGELOG.md library.json library.properties appveyor.yml CMakeLists.txt
git commit -m "Set version to $VERSION"
}
add_tag () {
CHANGES=$(awk '/\* /{ FOUND=1; print; next } { if (FOUND) exit}' CHANGELOG.md)
git tag -m "ArduinoJson $VERSION"$'\n'"$CHANGES" "$TAG"
}
push () {
git push --follow-tags
}
update_version_in_source
commit_new_version
add_tag
push
extras/scripts/build-arduino-package.sh
extras/scripts/build-single-header.sh
extras/scripts/wandbox/publish.sh "../ArduinoJson-$TAG.h"

View File

@@ -0,0 +1,60 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
//
// This example shows how to generate a JSON document with ArduinoJson.
#include <iostream>
#include "ArduinoJson.h"
int main() {
// Allocate the JSON document
//
// Inside the brackets, 200 is the RAM allocated to this document.
// Don't forget to change this value to match your requirement.
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<200> doc;
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonDocument doc(200);
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonDocument doc(200);
// Add values in the document
//
doc["sensor"] = "gps";
doc["time"] = 1351824120;
// Add an array.
//
JsonArray data = doc.createNestedArray("data");
data.add(48.756080);
data.add(2.302038);
// Generate the minified JSON and send it to STDOUT
//
serializeJson(doc, std::cout);
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
// Start a new line
std::cout << std::endl;
// Generate the prettified JSON and send it to STDOUT
//
serializeJsonPretty(doc, std::cout);
// The above line prints:
// {
// "sensor": "gps",
// "time": 1351824120,
// "data": [
// 48.756080,
// 2.302038
// ]
// }
}

View File

@@ -0,0 +1,59 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
//
// This example shows how to deserialize a JSON document with ArduinoJson.
#include <iostream>
#include "ArduinoJson.h"
int main() {
// Allocate the JSON document
//
// Inside the brackets, 200 is the capacity of the memory pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use https://arduinojson.org/v6/assistant to compute the capacity.
StaticJsonDocument<300> doc;
// StaticJsonDocument<N> allocates memory on the stack, it can be
// replaced by DynamicJsonDocument which allocates in the heap.
//
// DynamicJsonDocument doc(200);
// JSON input string.
//
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// the input buffer.
// If you use another type of input, ArduinoJson must copy the strings from
// the input to the JsonDocument, so you need to increase the capacity of the
// JsonDocument.
char json[] =
"{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}";
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, json);
// Test if parsing succeeds.
if (error) {
std::cerr << "deserializeJson() failed: " << error.c_str() << std::endl;
return 1;
}
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
std::cout << sensor << std::endl;
std::cout << time << std::endl;
std::cout << latitude << std::endl;
std::cout << longitude << std::endl;
return 0;
}

View File

@@ -0,0 +1,68 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
//
// This example shows how to generate a JSON document with ArduinoJson.
#include <iostream>
#include "ArduinoJson.h"
int main() {
// Allocate the JSON document
//
// Inside the brackets, 300 is the size of the memory pool in bytes.
// Don't forget to change this value to match your JSON document.
// Use https://arduinojson.org/assistant to compute the capacity.
StaticJsonDocument<300> doc;
// StaticJsonObject allocates memory on the stack, it can be
// replaced by DynamicJsonObject which allocates in the heap.
//
// DynamicJsonObject doc(200);
// MessagePack input string.
//
// It's better to use a char[] as shown here.
// If you use a const char* or a String, ArduinoJson will
// have to make a copy of the input in the JsonBuffer.
uint8_t input[] = {131, 166, 115, 101, 110, 115, 111, 114, 163, 103, 112, 115,
164, 116, 105, 109, 101, 206, 80, 147, 50, 248, 164, 100,
97, 116, 97, 146, 203, 64, 72, 96, 199, 58, 188, 148,
112, 203, 64, 2, 106, 146, 230, 33, 49, 169};
// This MessagePack document contains:
// {
// "sensor": "gps",
// "time": 1351824120,
// "data": [48.75608, 2.302038]
// }
// doc of the object tree.
//
// It's a reference to the JsonObject, the actual bytes are inside the
// JsonBuffer with all the other nodes of the object tree.
// Memory is freed when jsonBuffer goes out of scope.
DeserializationError error = deserializeMsgPack(doc, input);
// Test if parsing succeeds.
if (error) {
std::cerr << "deserializeMsgPack() failed: " << error.c_str() << std::endl;
return 1;
}
// Fetch values.
//
// Most of the time, you can rely on the implicit casts.
// In other case, you can do doc["time"].as<long>();
const char* sensor = doc["sensor"];
long time = doc["time"];
double latitude = doc["data"][0];
double longitude = doc["data"][1];
// Print values.
std::cout << sensor << std::endl;
std::cout << time << std::endl;
std::cout << latitude << std::endl;
std::cout << longitude << std::endl;
return 0;
}

View File

@@ -0,0 +1,29 @@
#!/usr/bin/env bash
set -eu
ARDUINOJSON_H="$1"
read_string() {
jq --slurp --raw-input '.' "$1"
}
compile() {
FILE_PATH="$(dirname $0)/$1.cpp"
cat >parameters.json <<END
{
"code":$(read_string "$FILE_PATH"),
"codes": [{"file":"ArduinoJson.h","code":$(read_string "$ARDUINOJSON_H")}],
"options": "warning",
"compiler": "gcc-4.9.3",
"save": true
}
END
URL=$(curl -sS -H "Content-type: application/json" -d @parameters.json https://wandbox.org/api/compile.json | jq --raw-output .url)
rm parameters.json
echo " $1: $URL"
}
compile "JsonGeneratorExample"
compile "JsonParserExample"
compile "MsgPackParserExample"

View File

@@ -0,0 +1,24 @@
# ArduinoJson - https://arduinojson.org
# Copyright Benoit Blanchon 2014-2021
# MIT License
add_subdirectory(catch)
link_libraries(ArduinoJson catch)
include_directories(Helpers)
add_subdirectory(FailingBuilds)
add_subdirectory(IntegrationTests)
add_subdirectory(JsonArray)
add_subdirectory(JsonDeserializer)
add_subdirectory(JsonDocument)
add_subdirectory(JsonObject)
add_subdirectory(JsonSerializer)
add_subdirectory(JsonVariant)
add_subdirectory(MemoryPool)
add_subdirectory(Misc)
add_subdirectory(MixedConfiguration)
add_subdirectory(MsgPackDeserializer)
add_subdirectory(MsgPackSerializer)
add_subdirectory(Numbers)
add_subdirectory(TextFormatter)

View File

@@ -0,0 +1,48 @@
# ArduinoJson - https://arduinojson.org
# Copyright Benoit Blanchon 2014-2021
# MIT License
macro(build_should_fail target)
set_target_properties(${target}
PROPERTIES
EXCLUDE_FROM_ALL TRUE
EXCLUDE_FROM_DEFAULT_BUILD TRUE
)
add_test(
NAME
${target}
COMMAND
${CMAKE_COMMAND} --build . --target ${target} --config $<CONFIGURATION>
WORKING_DIRECTORY
${CMAKE_BINARY_DIR}
)
set_tests_properties(${target}
PROPERTIES
WILL_FAIL TRUE
LABELS "WillFail;Catch"
)
endmacro()
add_executable(Issue978 Issue978.cpp)
build_should_fail(Issue978)
add_executable(Issue1189 Issue1189.cpp)
build_should_fail(Issue1189)
add_executable(read_long_long read_long_long.cpp)
set_property(TARGET read_long_long PROPERTY CXX_STANDARD 11)
build_should_fail(read_long_long)
add_executable(write_long_long write_long_long.cpp)
set_property(TARGET write_long_long PROPERTY CXX_STANDARD 11)
build_should_fail(write_long_long)
add_executable(delete_jsondocument delete_jsondocument.cpp)
build_should_fail(delete_jsondocument)
add_executable(variant_as_char variant_as_char.cpp)
build_should_fail(variant_as_char)
add_executable(assign_char assign_char.cpp)
build_should_fail(assign_char)

View File

@@ -0,0 +1,13 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
// a function should not be able to get a JsonDocument by value
void f(JsonDocument) {}
int main() {
DynamicJsonDocument doc(1024);
f(doc);
}

View File

@@ -0,0 +1,13 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
struct Stream {};
int main() {
Stream* stream = 0;
DynamicJsonDocument doc(1024);
deserializeJson(doc, stream);
}

View File

@@ -0,0 +1,12 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
// See issue #1498
int main() {
DynamicJsonDocument doc(1024);
doc["dummy"] = 'A';
}

View File

@@ -0,0 +1,12 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
struct Stream {};
int main() {
JsonDocument* doc = new DynamicJsonDocument(42);
delete doc;
}

View File

@@ -0,0 +1,20 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#define ARDUINOJSON_USE_LONG_LONG 0
#include <ArduinoJson.h>
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8
#error This test requires sizeof(long) < 8
#endif
#if !ARDUINOJSON_HAS_LONG_LONG
#error This test requires C++11
#endif
ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(long long)
int main() {
DynamicJsonDocument doc(1024);
doc["dummy"].as<long long>();
}

View File

@@ -0,0 +1,12 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
// See issue #1498
int main() {
DynamicJsonDocument doc(1024);
doc["dummy"].as<char>();
}

View File

@@ -0,0 +1,19 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#define ARDUINOJSON_USE_LONG_LONG 0
#include <ArduinoJson.h>
#if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ >= 8
#error This test requires sizeof(long) < 8
#endif
#if !ARDUINOJSON_HAS_LONG_LONG
#error This test requires C++11
#endif
int main() {
DynamicJsonDocument doc(1024);
doc["dummy"] = static_cast<long long>(42);
}

View File

@@ -0,0 +1,9 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include "api/Print.h"
#include "api/Stream.h"
#include "api/String.h"

View File

@@ -0,0 +1,26 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <sstream>
class CustomReader {
std::stringstream _stream;
public:
CustomReader(const char* input) : _stream(input) {}
int read() {
return _stream.get();
}
size_t readBytes(char* buffer, size_t length) {
_stream.read(buffer, static_cast<std::streamsize>(length));
return static_cast<size_t>(_stream.gcount());
}
private:
CustomReader(const CustomReader&);
};

View File

@@ -0,0 +1,33 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
class Print {
public:
virtual ~Print() {}
virtual size_t write(uint8_t) = 0;
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
size_t write(const char *str) {
if (!str)
return 0;
return write(reinterpret_cast<const uint8_t *>(str), strlen(str));
}
size_t write(const char *buffer, size_t size) {
return write(reinterpret_cast<const uint8_t *>(buffer), size);
}
};
class Printable {
public:
virtual ~Printable() {}
virtual size_t printTo(Print &p) const = 0;
};

View File

@@ -0,0 +1,14 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
// Reproduces Arduino's Stream class
class Stream // : public Print
{
public:
virtual ~Stream() {}
virtual int read() = 0;
virtual size_t readBytes(char *buffer, size_t length) = 0;
};

View File

@@ -0,0 +1,45 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#pragma once
#include <string>
// Reproduces Arduino's String class
class String {
public:
String() {}
explicit String(const char* s) : _str(s) {}
String& operator+=(const char* rhs) {
_str += rhs;
return *this;
}
size_t length() const {
return _str.size();
}
const char* c_str() const {
return _str.c_str();
}
bool operator==(const char* s) const {
return _str == s;
}
friend std::ostream& operator<<(std::ostream& lhs, const ::String& rhs) {
lhs << rhs._str;
return lhs;
}
private:
std::string _str;
};
class StringSumHelper;
inline bool operator==(const std::string& lhs, const ::String& rhs) {
return lhs == rhs.c_str();
}

View File

@@ -0,0 +1,42 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <stdint.h> // uint8_t
#include <string.h> // strcmp, strlen...
#define PROGMEM
class __FlashStringHelper;
inline const void* convertPtrToFlash(const void* s) {
return reinterpret_cast<const char*>(s) + 42;
}
inline const void* convertFlashToPtr(const void* s) {
return reinterpret_cast<const char*>(s) - 42;
}
#define PSTR(X) reinterpret_cast<const char*>(convertPtrToFlash(X))
#define F(X) reinterpret_cast<const __FlashStringHelper*>(PSTR(X))
inline uint8_t pgm_read_byte(const void* p) {
return *reinterpret_cast<const uint8_t*>(convertFlashToPtr(p));
}
inline void* pgm_read_ptr(const void* p) {
return *reinterpret_cast<void* const*>(convertFlashToPtr(p));
}
inline float pgm_read_float(const void* p) {
return *reinterpret_cast<const float*>(convertFlashToPtr(p));
}
inline uint32_t pgm_read_dword(const void* p) {
return *reinterpret_cast<const uint32_t*>(convertFlashToPtr(p));
}
#define ARDUINOJSON_DEFINE_STATIC_ARRAY(type, name, value) \
static type const ARDUINOJSON_CONCAT2(name, _progmem)[] = value; \
static type const* name = reinterpret_cast<type const*>( \
convertPtrToFlash(ARDUINOJSON_CONCAT2(name, _progmem)));

View File

@@ -0,0 +1,24 @@
# ArduinoJson - https://arduinojson.org
# Copyright Benoit Blanchon 2014-2021
# MIT License
add_executable(IntegrationTests
gbathree.cpp
issue772.cpp
round_trip.cpp
openweathermap.cpp
)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
target_compile_options(IntegrationTests
PUBLIC
-fsingle-precision-constant # issue 544
)
endif()
add_test(IntegrationTests IntegrationTests)
set_tests_properties(IntegrationTests
PROPERTIES
LABELS "Catch"
)

View File

@@ -0,0 +1,210 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Gbathree") {
DynamicJsonDocument doc(4096);
DeserializationError error = deserializeJson(
doc,
"{\"protocol_name\":\"fluorescence\",\"repeats\":1,\"wait\":0,"
"\"averages\":1,\"measurements\":3,\"meas2_light\":15,\"meas1_"
"baseline\":0,\"act_light\":20,\"pulsesize\":25,\"pulsedistance\":"
"10000,\"actintensity1\":50,\"actintensity2\":255,\"measintensity\":"
"255,\"calintensity\":255,\"pulses\":[50,50,50],\"act\":[2,1,2,2],"
"\"red\":[2,2,2,2],\"detectors\":[[34,34,34,34],[34,34,34,34],[34,"
"34,34,34],[34,34,34,34]],\"alta\":[2,2,2,2],\"altb\":[2,2,2,2],"
"\"measlights\":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,"
"15,15]],\"measlights2\":[[15,15,15,15],[15,15,15,15],[15,15,15,15],"
"[15,15,15,15]],\"altc\":[2,2,2,2],\"altd\":[2,2,2,2]}");
JsonObject root = doc.as<JsonObject>();
SECTION("Success") {
REQUIRE(error == DeserializationError::Ok);
}
SECTION("ProtocolName") {
REQUIRE("fluorescence" == root["protocol_name"]);
}
SECTION("Repeats") {
REQUIRE(1 == root["repeats"]);
}
SECTION("Wait") {
REQUIRE(0 == root["wait"]);
}
SECTION("Measurements") {
REQUIRE(3 == root["measurements"]);
}
SECTION("Meas2_Light") {
REQUIRE(15 == root["meas2_light"]);
}
SECTION("Meas1_Baseline") {
REQUIRE(0 == root["meas1_baseline"]);
}
SECTION("Act_Light") {
REQUIRE(20 == root["act_light"]);
}
SECTION("Pulsesize") {
REQUIRE(25 == root["pulsesize"]);
}
SECTION("Pulsedistance") {
REQUIRE(10000 == root["pulsedistance"]);
}
SECTION("Actintensity1") {
REQUIRE(50 == root["actintensity1"]);
}
SECTION("Actintensity2") {
REQUIRE(255 == root["actintensity2"]);
}
SECTION("Measintensity") {
REQUIRE(255 == root["measintensity"]);
}
SECTION("Calintensity") {
REQUIRE(255 == root["calintensity"]);
}
SECTION("Pulses") {
// "pulses":[50,50,50]
JsonArray array = root["pulses"];
REQUIRE(array.isNull() == false);
REQUIRE(3 == array.size());
for (size_t i = 0; i < 3; i++) {
REQUIRE(50 == array[i]);
}
}
SECTION("Act") {
// "act":[2,1,2,2]
JsonArray array = root["act"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
REQUIRE(2 == array[0]);
REQUIRE(1 == array[1]);
REQUIRE(2 == array[2]);
REQUIRE(2 == array[3]);
}
SECTION("Detectors") {
// "detectors":[[34,34,34,34],[34,34,34,34],[34,34,34,34],[34,34,34,34]]
JsonArray array = root["detectors"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
JsonArray nestedArray = array[i];
REQUIRE(4 == nestedArray.size());
for (size_t j = 0; j < 4; j++) {
REQUIRE(34 == nestedArray[j]);
}
}
}
SECTION("Alta") {
// alta:[2,2,2,2]
JsonArray array = root["alta"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
SECTION("Altb") {
// altb:[2,2,2,2]
JsonArray array = root["altb"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
SECTION("Measlights") {
// "measlights":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]]
JsonArray array = root["measlights"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
JsonArray nestedArray = array[i];
REQUIRE(4 == nestedArray.size());
for (size_t j = 0; j < 4; j++) {
REQUIRE(15 == nestedArray[j]);
}
}
}
SECTION("Measlights2") {
// "measlights2":[[15,15,15,15],[15,15,15,15],[15,15,15,15],[15,15,15,15]]
JsonArray array = root["measlights2"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
JsonArray nestedArray = array[i];
REQUIRE(4 == nestedArray.size());
for (size_t j = 0; j < 4; j++) {
REQUIRE(15 == nestedArray[j]);
}
}
}
SECTION("Altc") {
// altc:[2,2,2,2]
JsonArray array = root["altc"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
SECTION("Altd") {
// altd:[2,2,2,2]
JsonArray array = root["altd"];
REQUIRE(array.isNull() == false);
REQUIRE(4 == array.size());
for (size_t i = 0; i < 4; i++) {
REQUIRE(2 == array[i]);
}
}
}

View File

@@ -0,0 +1,28 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
// https://github.com/bblanchon/ArduinoJson/issues/772
TEST_CASE("Issue772") {
DynamicJsonDocument doc1(4096);
DynamicJsonDocument doc2(4096);
DeserializationError err;
std::string data =
"{\"state\":{\"reported\":{\"timestamp\":\"2018-07-02T09:40:12Z\","
"\"mac\":\"2C3AE84FC076\",\"firmwareVersion\":\"v0.2.7-5-gf4d4d78\","
"\"visibleLight\":261,\"infraRed\":255,\"ultraViolet\":0.02,"
"\"Temperature\":26.63,\"Pressure\":101145.7,\"Humidity\":54.79883,"
"\"Vbat\":4.171261,\"soilMoisture\":0,\"ActB\":0}}}";
err = deserializeJson(doc1, data);
REQUIRE(err == DeserializationError::Ok);
data = "";
serializeMsgPack(doc1, data);
err = deserializeMsgPack(doc2, data);
REQUIRE(err == DeserializationError::Ok);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,82 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
void check(std::string originalJson) {
DynamicJsonDocument doc(16384);
std::string prettyJson;
deserializeJson(doc, originalJson);
serializeJsonPretty(doc, prettyJson);
std::string finalJson;
deserializeJson(doc, originalJson);
serializeJson(doc, finalJson);
REQUIRE(originalJson == finalJson);
}
TEST_CASE("Round Trip: parse -> prettyPrint -> parse -> print") {
SECTION("OpenWeatherMap") {
check(
"{\"coord\":{\"lon\":145.77,\"lat\":-16.92},\"sys\":{\"type\":1,\"id\":"
"8166,\"message\":0.1222,\"country\":\"AU\",\"sunrise\":1414784325,"
"\"sunset\":1414830137},\"weather\":[{\"id\":801,\"main\":\"Clouds\","
"\"description\":\"few clouds\",\"icon\":\"02n\"}],\"base\":\"cmc "
"stations\",\"main\":{\"temp\":296.15,\"pressure\":1014,\"humidity\":"
"83,\"temp_min\":296.15,\"temp_max\":296.15},\"wind\":{\"speed\":2.22,"
"\"deg\":114.501},\"clouds\":{\"all\":20},\"dt\":1414846800,\"id\":"
"2172797,\"name\":\"Cairns\",\"cod\":200}");
}
SECTION("YahooQueryLanguage") {
check(
"{\"query\":{\"count\":40,\"created\":\"2014-11-01T14:16:49Z\","
"\"lang\":\"fr-FR\",\"results\":{\"item\":[{\"title\":\"Burkina army "
"backs Zida as interim leader\"},{\"title\":\"British jets intercept "
"Russian bombers\"},{\"title\":\"Doubts chip away at nation's most "
"trusted agencies\"},{\"title\":\"Cruise ship stuck off Norway, no "
"damage\"},{\"title\":\"U.S. military launches 10 air strikes in "
"Syria, Iraq\"},{\"title\":\"Blackout hits Bangladesh as line from "
"India fails\"},{\"title\":\"Burkina Faso president in Ivory Coast "
"after ouster\"},{\"title\":\"Kurds in Turkey rally to back city "
"besieged by IS\"},{\"title\":\"A majority of Scots would vote for "
"independence now:poll\"},{\"title\":\"Tunisia elections possible "
"model for region\"},{\"title\":\"Islamic State kills 85 more members "
"of Iraqi tribe\"},{\"title\":\"Iraqi officials:IS extremists line "
"up, kill 50\"},{\"title\":\"Burkina Faso army backs presidential "
"guard official to lead transition\"},{\"title\":\"Kurdish peshmerga "
"arrive with weapons in Syria's Kobani\"},{\"title\":\"Driver sought "
"in crash that killed 3 on Halloween\"},{\"title\":\"Ex-Marine arrives "
"in US after release from Mexico jail\"},{\"title\":\"UN panel "
"scrambling to finish climate report\"},{\"title\":\"Investigators, "
"Branson go to spacecraft crash site\"},{\"title\":\"Soldiers vie for "
"power after Burkina Faso president quits\"},{\"title\":\"For a man "
"without a party, turnout is big test\"},{\"title\":\"'We just had a "
"hunch':US marshals nab Eric Frein\"},{\"title\":\"Boko Haram leader "
"threatens to kill German hostage\"},{\"title\":\"Nurse free to move "
"about as restrictions eased\"},{\"title\":\"Former Burkina president "
"Compaore arrives in Ivory Coast:sources\"},{\"title\":\"Libyan port "
"rebel leader refuses to hand over oil ports to rival "
"group\"},{\"title\":\"Iraqi peshmerga fighters prepare for Syria "
"battle\"},{\"title\":\"1 Dem Senate candidate welcoming Obama's "
"help\"},{\"title\":\"Bikers cancel party after police recover "
"bar\"},{\"title\":\"New question in Texas:Can Davis survive "
"defeat?\"},{\"title\":\"Ukraine rebels to hold election, despite "
"criticism\"},{\"title\":\"Iraqi officials say Islamic State group "
"lines up, kills 50 tribesmen, women in Anbar "
"province\"},{\"title\":\"James rebounds, leads Cavaliers past "
"Bulls\"},{\"title\":\"UK warns travelers they could be terror "
"targets\"},{\"title\":\"Hello Kitty celebrates 40th "
"birthday\"},{\"title\":\"A look at people killed during space "
"missions\"},{\"title\":\"Nigeria's purported Boko Haram leader says "
"has 'married off' girls:AFP\"},{\"title\":\"Mexico orders immediate "
"release of Marine veteran\"},{\"title\":\"As election closes in, "
"Obama on center stage\"},{\"title\":\"Body of Zambian president "
"arrives home\"},{\"title\":\"South Africa arrests 2 Vietnamese for "
"poaching\"}]}}}");
}
}

View File

@@ -0,0 +1,27 @@
# ArduinoJson - https://arduinojson.org
# Copyright Benoit Blanchon 2014-2021
# MIT License
add_executable(JsonArrayTests
add.cpp
copyArray.cpp
createNested.cpp
equals.cpp
get.cpp
isNull.cpp
iterator.cpp
memoryUsage.cpp
nesting.cpp
remove.cpp
size.cpp
std_string.cpp
subscript.cpp
undefined.cpp
)
add_test(JsonArray JsonArrayTests)
set_tests_properties(JsonArray
PROPERTIES
LABELS "Catch"
)

View File

@@ -0,0 +1,138 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::add()") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
SECTION("int") {
array.add(123);
REQUIRE(123 == array[0].as<int>());
REQUIRE(array[0].is<int>());
REQUIRE(array[0].is<double>());
}
SECTION("double") {
array.add(123.45);
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(array[0].is<double>());
REQUIRE_FALSE(array[0].is<bool>());
}
SECTION("bool") {
array.add(true);
REQUIRE(true == array[0].as<bool>());
REQUIRE(array[0].is<bool>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("const char*") {
const char* str = "hello";
array.add(str);
REQUIRE(str == array[0].as<std::string>());
REQUIRE(array[0].is<const char*>());
REQUIRE_FALSE(array[0].is<int>());
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("vla") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add(vla);
REQUIRE(std::string("world") == array[0]);
}
#endif
SECTION("nested array") {
DynamicJsonDocument doc2(4096);
JsonArray arr = doc2.to<JsonArray>();
array.add(arr);
REQUIRE(arr == array[0].as<JsonArray>());
REQUIRE(array[0].is<JsonArray>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2(4096);
JsonObject obj = doc2.to<JsonObject>();
array.add(obj);
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(array[0].is<JsonObject>());
REQUIRE_FALSE(array[0].is<int>());
}
SECTION("array subscript") {
const char* str = "hello";
DynamicJsonDocument doc2(4096);
JsonArray arr = doc2.to<JsonArray>();
arr.add(str);
array.add(arr[0]);
REQUIRE(str == array[0]);
}
SECTION("object subscript") {
const char* str = "hello";
DynamicJsonDocument doc2(4096);
JsonObject obj = doc2.to<JsonObject>();
obj["x"] = str;
array.add(obj["x"]);
REQUIRE(str == array[0]);
}
SECTION("should not duplicate const char*") {
array.add("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate char*") {
array.add(const_cast<char*>("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
array.add(std::string("world"));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should not duplicate serialized(const char*)") {
array.add(serialized("{}"));
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(char*)") {
array.add(serialized(const_cast<char*>("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(2);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("{}")));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(2);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate serialized(std::string)") {
array.add(serialized(std::string("\0XX", 3)));
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(3);
REQUIRE(expectedSize == doc.memoryUsage());
}
}

View File

@@ -0,0 +1,279 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("copyArray()") {
SECTION("int[] -> JsonArray") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
char json[32];
int source[] = {1, 2, 3};
bool ok = copyArray(source, array);
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[1,2,3]") == json);
}
SECTION("std::string[] -> JsonArray") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
char json[32];
std::string source[] = {"a", "b", "c"};
bool ok = copyArray(source, array);
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
}
SECTION("int[] -> JsonDocument") {
DynamicJsonDocument doc(4096);
char json[32];
int source[] = {1, 2, 3};
bool ok = copyArray(source, doc);
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("[1,2,3]") == json);
}
SECTION("int[] -> MemberProxy") {
DynamicJsonDocument doc(4096);
char json[32];
int source[] = {1, 2, 3};
bool ok = copyArray(source, doc["data"]);
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("{\"data\":[1,2,3]}") == json);
}
SECTION("int[] -> JsonArray, but not enough memory") {
const size_t SIZE = JSON_ARRAY_SIZE(2);
StaticJsonDocument<SIZE> doc;
JsonArray array = doc.to<JsonArray>();
char json[32];
int source[] = {1, 2, 3};
bool ok = copyArray(source, array);
REQUIRE_FALSE(ok);
serializeJson(array, json);
CHECK(std::string("[1,2]") == json);
}
SECTION("int[][] -> JsonArray") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
char json[32];
int source[][3] = {{1, 2, 3}, {4, 5, 6}};
bool ok = copyArray(source, array);
CHECK(ok);
serializeJson(array, json);
CHECK(std::string("[[1,2,3],[4,5,6]]") == json);
}
SECTION("int[][] -> MemberProxy") {
DynamicJsonDocument doc(4096);
char json[32];
int source[][3] = {{1, 2, 3}, {4, 5, 6}};
bool ok = copyArray(source, doc["data"]);
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("{\"data\":[[1,2,3],[4,5,6]]}") == json);
}
SECTION("int[][] -> JsonDocument") {
DynamicJsonDocument doc(4096);
char json[32];
int source[][3] = {{1, 2, 3}, {4, 5, 6}};
bool ok = copyArray(source, doc);
CHECK(ok);
serializeJson(doc, json);
CHECK(std::string("[[1,2,3],[4,5,6]]") == json);
}
SECTION("int[][] -> JsonArray, but not enough memory") {
const size_t SIZE =
JSON_ARRAY_SIZE(2) + JSON_ARRAY_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonDocument<SIZE> doc;
JsonArray array = doc.to<JsonArray>();
char json[32] = "";
int source[][3] = {{1, 2, 3}, {4, 5, 6}};
CAPTURE(SIZE)
bool ok = copyArray(source, array);
CAPTURE(doc.memoryUsage());
CHECK_FALSE(ok);
serializeJson(array, json);
CHECK(std::string("[[1,2,3],[4,5]]") == json);
}
SECTION("JsonArray -> int[], with more space than needed") {
DynamicJsonDocument doc(4096);
char json[] = "[1,2,3]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
JsonArray array = doc.as<JsonArray>();
int destination[4] = {0};
size_t result = copyArray(array, destination);
CHECK(3 == result);
CHECK(1 == destination[0]);
CHECK(2 == destination[1]);
CHECK(3 == destination[2]);
CHECK(0 == destination[3]);
}
SECTION("JsonArray -> int[], without enough space") {
DynamicJsonDocument doc(4096);
char json[] = "[1,2,3]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
JsonArray array = doc.as<JsonArray>();
int destination[2] = {0};
size_t result = copyArray(array, destination);
CHECK(2 == result);
CHECK(1 == destination[0]);
CHECK(2 == destination[1]);
}
SECTION("JsonArray -> std::string[]") {
DynamicJsonDocument doc(4096);
char json[] = "[\"a\",\"b\",\"c\"]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
JsonArray array = doc.as<JsonArray>();
std::string destination[4];
size_t result = copyArray(array, destination);
CHECK(3 == result);
CHECK("a" == destination[0]);
CHECK("b" == destination[1]);
CHECK("c" == destination[2]);
CHECK("" == destination[3]);
}
SECTION("JsonDocument -> int[]") {
DynamicJsonDocument doc(4096);
char json[] = "[1,2,3]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
int destination[4] = {0};
size_t result = copyArray(doc, destination);
CHECK(3 == result);
CHECK(1 == destination[0]);
CHECK(2 == destination[1]);
CHECK(3 == destination[2]);
CHECK(0 == destination[3]);
}
SECTION("MemberProxy -> int[]") {
DynamicJsonDocument doc(4096);
char json[] = "{\"data\":[1,2,3]}";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
int destination[4] = {0};
size_t result = copyArray(doc["data"], destination);
CHECK(3 == result);
CHECK(1 == destination[0]);
CHECK(2 == destination[1]);
CHECK(3 == destination[2]);
CHECK(0 == destination[3]);
}
SECTION("ElementProxy -> int[]") {
DynamicJsonDocument doc(4096);
char json[] = "[[1,2,3]]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
int destination[4] = {0};
size_t result = copyArray(doc[0], destination);
CHECK(3 == result);
CHECK(1 == destination[0]);
CHECK(2 == destination[1]);
CHECK(3 == destination[2]);
CHECK(0 == destination[3]);
}
SECTION("JsonArray -> int[][]") {
DynamicJsonDocument doc(4096);
char json[] = "[[1,2],[3],[4]]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
JsonArray array = doc.as<JsonArray>();
int destination[3][2] = {{0}};
copyArray(array, destination);
CHECK(1 == destination[0][0]);
CHECK(2 == destination[0][1]);
CHECK(3 == destination[1][0]);
CHECK(0 == destination[1][1]);
CHECK(4 == destination[2][0]);
CHECK(0 == destination[2][1]);
}
SECTION("JsonDocument -> int[][]") {
DynamicJsonDocument doc(4096);
char json[] = "[[1,2],[3],[4]]";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
int destination[3][2] = {{0}};
copyArray(doc, destination);
CHECK(1 == destination[0][0]);
CHECK(2 == destination[0][1]);
CHECK(3 == destination[1][0]);
CHECK(0 == destination[1][1]);
CHECK(4 == destination[2][0]);
CHECK(0 == destination[2][1]);
}
SECTION("MemberProxy -> int[][]") {
DynamicJsonDocument doc(4096);
char json[] = "{\"data\":[[1,2],[3],[4]]}";
DeserializationError err = deserializeJson(doc, json);
CHECK(err == DeserializationError::Ok);
int destination[3][2] = {{0}};
copyArray(doc["data"], destination);
CHECK(1 == destination[0][0]);
CHECK(2 == destination[0][1]);
CHECK(3 == destination[1][0]);
CHECK(0 == destination[1][1]);
CHECK(4 == destination[2][0]);
CHECK(0 == destination[2][1]);
}
}

View File

@@ -0,0 +1,21 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray basics") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
SECTION("CreateNestedArray") {
JsonArray arr = array.createNestedArray();
REQUIRE(arr == array[0].as<JsonArray>());
}
SECTION("CreateNestedObject") {
JsonObject obj = array.createNestedObject();
REQUIRE(obj == array[0].as<JsonObject>());
}
}

View File

@@ -0,0 +1,69 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::operator==()") {
DynamicJsonDocument doc1(4096);
JsonArray array1 = doc1.to<JsonArray>();
JsonArrayConst array1c = array1;
DynamicJsonDocument doc2(4096);
JsonArray array2 = doc2.to<JsonArray>();
JsonArrayConst array2c = array2;
SECTION("should return false when arrays differ") {
array1.add("coucou");
array2.add(1);
REQUIRE_FALSE(array1 == array2);
REQUIRE_FALSE(array1c == array2c);
}
SECTION("should return false when LHS has more elements") {
array1.add(1);
array1.add(2);
array2.add(1);
REQUIRE_FALSE(array1 == array2);
REQUIRE_FALSE(array1c == array2c);
}
SECTION("should return false when RHS has more elements") {
array1.add(1);
array2.add(1);
array2.add(2);
REQUIRE_FALSE(array1 == array2);
REQUIRE_FALSE(array1c == array2c);
}
SECTION("should return true when arrays equal") {
array1.add("coucou");
array2.add("coucou");
REQUIRE(array1 == array2);
REQUIRE(array1c == array2c);
}
SECTION("should return false when RHS is null") {
JsonArray null;
REQUIRE_FALSE(array1 == null);
}
SECTION("should return false when LHS is null") {
JsonArray null;
REQUIRE_FALSE(null == array1);
}
SECTION("should return true when both are null") {
JsonArray null1;
JsonArray null2;
REQUIRE(null1 == null2);
}
}

View File

@@ -0,0 +1,16 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::get()") {
DynamicJsonDocument doc(4096);
deserializeJson(doc, "[1,2,3]");
JsonArray array = doc.as<JsonArray>();
SECTION("Overflow") {
REQUIRE(array.getElement(3).isNull());
}
}

View File

@@ -0,0 +1,58 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::isNull()") {
SECTION("returns true") {
JsonArray arr;
REQUIRE(arr.isNull() == true);
}
SECTION("returns false") {
DynamicJsonDocument doc(4096);
JsonArray arr = doc.to<JsonArray>();
REQUIRE(arr.isNull() == false);
}
}
TEST_CASE("JsonArrayConst::isNull()") {
SECTION("returns true") {
JsonArrayConst arr;
REQUIRE(arr.isNull() == true);
}
SECTION("returns false") {
DynamicJsonDocument doc(4096);
JsonArrayConst arr = doc.to<JsonArray>();
REQUIRE(arr.isNull() == false);
}
}
TEST_CASE("JsonArray::operator bool()") {
SECTION("returns false") {
JsonArray arr;
REQUIRE(static_cast<bool>(arr) == false);
}
SECTION("returns true") {
DynamicJsonDocument doc(4096);
JsonArray arr = doc.to<JsonArray>();
REQUIRE(static_cast<bool>(arr) == true);
}
}
TEST_CASE("JsonArrayConst::operator bool()") {
SECTION("returns false") {
JsonArrayConst arr;
REQUIRE(static_cast<bool>(arr) == false);
}
SECTION("returns true") {
DynamicJsonDocument doc(4096);
JsonArrayConst arr = doc.to<JsonArray>();
REQUIRE(static_cast<bool>(arr) == true);
}
}

View File

@@ -0,0 +1,52 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
template <typename TArray>
static void run_iterator_test() {
StaticJsonDocument<JSON_ARRAY_SIZE(2)> doc;
JsonArray tmp = doc.to<JsonArray>();
tmp.add(12);
tmp.add(34);
TArray array = tmp;
typename TArray::iterator it = array.begin();
typename TArray::iterator end = array.end();
REQUIRE(end != it);
REQUIRE(12 == it->template as<int>());
REQUIRE(12 == static_cast<int>(*it));
++it;
REQUIRE(end != it);
REQUIRE(34 == it->template as<int>());
REQUIRE(34 == static_cast<int>(*it));
++it;
REQUIRE(end == it);
}
TEST_CASE("JsonArray::begin()/end()") {
SECTION("Non null JsonArray") {
run_iterator_test<JsonArray>();
}
SECTION("Null JsonArray") {
JsonArray array;
REQUIRE(array.begin() == array.end());
}
}
TEST_CASE("JsonArrayConst::begin()/end()") {
SECTION("Non null JsonArrayConst") {
run_iterator_test<JsonArrayConst>();
}
SECTION("Null JsonArrayConst") {
JsonArrayConst array;
REQUIRE(array.begin() == array.end());
}
}

View File

@@ -0,0 +1,42 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::memoryUsage()") {
DynamicJsonDocument doc(4096);
JsonArray arr = doc.to<JsonArray>();
SECTION("return 0 if uninitialized") {
JsonArray unitialized;
REQUIRE(unitialized.memoryUsage() == 0);
}
SECTION("JSON_ARRAY_SIZE(0) if empty") {
REQUIRE(arr.memoryUsage() == JSON_ARRAY_SIZE(0));
}
SECTION("JSON_ARRAY_SIZE(1) after add") {
arr.add("hello");
REQUIRE(arr.memoryUsage() == JSON_ARRAY_SIZE(1));
}
SECTION("includes the size of the string") {
arr.add(std::string("hello"));
REQUIRE(arr.memoryUsage() == JSON_ARRAY_SIZE(1) + 6);
}
SECTION("includes the size of the nested array") {
JsonArray nested = arr.createNestedArray();
nested.add(42);
REQUIRE(arr.memoryUsage() == 2 * JSON_ARRAY_SIZE(1));
}
SECTION("includes the size of the nested arrect") {
JsonObject nested = arr.createNestedObject();
nested["hello"] = "world";
REQUIRE(arr.memoryUsage() == JSON_OBJECT_SIZE(1) + JSON_ARRAY_SIZE(1));
}
}

View File

@@ -0,0 +1,35 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::nesting()") {
DynamicJsonDocument doc(4096);
JsonArray arr = doc.to<JsonArray>();
SECTION("return 0 if uninitialized") {
JsonArray unitialized;
REQUIRE(unitialized.nesting() == 0);
}
SECTION("returns 1 for empty array") {
REQUIRE(arr.nesting() == 1);
}
SECTION("returns 1 for flat array") {
arr.add("hello");
REQUIRE(arr.nesting() == 1);
}
SECTION("returns 2 with nested array") {
arr.createNestedArray();
REQUIRE(arr.nesting() == 2);
}
SECTION("returns 2 with nested object") {
arr.createNestedObject();
REQUIRE(arr.nesting() == 2);
}
}

View File

@@ -0,0 +1,79 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::remove()") {
DynamicJsonDocument doc(4096);
JsonArray _array = doc.to<JsonArray>();
_array.add(1);
_array.add(2);
_array.add(3);
SECTION("RemoveFirstByIndex") {
_array.remove(0);
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 2);
REQUIRE(_array[1] == 3);
}
SECTION("RemoveMiddleByIndex") {
_array.remove(1);
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 1);
REQUIRE(_array[1] == 3);
}
SECTION("RemoveLastByIndex") {
_array.remove(2);
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 1);
REQUIRE(_array[1] == 2);
}
SECTION("RemoveFirstByIterator") {
JsonArray::iterator it = _array.begin();
_array.remove(it);
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 2);
REQUIRE(_array[1] == 3);
}
SECTION("RemoveMiddleByIterator") {
JsonArray::iterator it = _array.begin();
++it;
_array.remove(it);
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 1);
REQUIRE(_array[1] == 3);
}
SECTION("RemoveLastByIterator") {
JsonArray::iterator it = _array.begin();
++it;
++it;
_array.remove(it);
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 1);
REQUIRE(_array[1] == 2);
}
SECTION("In a loop") {
for (JsonArray::iterator it = _array.begin(); it != _array.end(); ++it) {
if (*it == 2)
_array.remove(it);
}
REQUIRE(2 == _array.size());
REQUIRE(_array[0] == 1);
REQUIRE(_array[1] == 3);
}
}

View File

@@ -0,0 +1,31 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("JsonArray::size()") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
SECTION("returns 0 is empty") {
REQUIRE(0U == array.size());
}
SECTION("increases after add()") {
array.add("hello");
REQUIRE(1U == array.size());
array.add("world");
REQUIRE(2U == array.size());
}
SECTION("remains the same after replacing an element") {
array.add("hello");
REQUIRE(1U == array.size());
array[0] = "hello";
REQUIRE(1U == array.size());
}
}

View File

@@ -0,0 +1,31 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
static void eraseString(std::string &str) {
char *p = const_cast<char *>(str.c_str());
while (*p) *p++ = '*';
}
TEST_CASE("std::string") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
SECTION("add()") {
std::string value("hello");
array.add(value);
eraseString(value);
REQUIRE(std::string("hello") == array[0]);
}
SECTION("operator[]") {
std::string value("world");
array.add("hello");
array[0] = value;
eraseString(value);
REQUIRE(std::string("world") == array[0]);
}
}

View File

@@ -0,0 +1,174 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <stdint.h>
#include <catch.hpp>
TEST_CASE("JsonArray::operator[]") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
SECTION("Pad with null") {
array[2] = 2;
array[5] = 5;
REQUIRE(array.size() == 6);
REQUIRE(array[0].isNull() == true);
REQUIRE(array[1].isNull() == true);
REQUIRE(array[2].isNull() == false);
REQUIRE(array[3].isNull() == true);
REQUIRE(array[4].isNull() == true);
REQUIRE(array[5].isNull() == false);
REQUIRE(array[2] == 2);
REQUIRE(array[5] == 5);
}
SECTION("int") {
array[0] = 123;
REQUIRE(123 == array[0].as<int>());
REQUIRE(true == array[0].is<int>());
REQUIRE(false == array[0].is<bool>());
}
#if ARDUINOJSON_USE_LONG_LONG
SECTION("long long") {
array[0] = 9223372036854775807;
REQUIRE(9223372036854775807 == array[0].as<int64_t>());
REQUIRE(true == array[0].is<int64_t>());
REQUIRE(false == array[0].is<int32_t>());
REQUIRE(false == array[0].is<bool>());
}
#endif
SECTION("double") {
array[0] = 123.45;
REQUIRE(123.45 == array[0].as<double>());
REQUIRE(true == array[0].is<double>());
REQUIRE(false == array[0].is<int>());
}
SECTION("bool") {
array[0] = true;
REQUIRE(true == array[0].as<bool>());
REQUIRE(true == array[0].is<bool>());
REQUIRE(false == array[0].is<int>());
}
SECTION("const char*") {
const char* str = "hello";
array[0] = str;
REQUIRE(str == array[0].as<const char*>());
REQUIRE(true == array[0].is<const char*>());
REQUIRE(false == array[0].is<int>());
}
SECTION("nested array") {
DynamicJsonDocument doc2(4096);
JsonArray arr2 = doc2.to<JsonArray>();
array[0] = arr2;
REQUIRE(arr2 == array[0].as<JsonArray>());
REQUIRE(true == array[0].is<JsonArray>());
REQUIRE(false == array[0].is<int>());
}
SECTION("nested object") {
DynamicJsonDocument doc2(4096);
JsonObject obj = doc2.to<JsonObject>();
array[0] = obj;
REQUIRE(obj == array[0].as<JsonObject>());
REQUIRE(true == array[0].is<JsonObject>());
REQUIRE(false == array[0].is<int>());
}
SECTION("array subscript") {
DynamicJsonDocument doc2(4096);
JsonArray arr2 = doc2.to<JsonArray>();
const char* str = "hello";
arr2.add(str);
array[0] = arr2[0];
REQUIRE(str == array[0]);
}
SECTION("object subscript") {
const char* str = "hello";
DynamicJsonDocument doc2(4096);
JsonObject obj = doc2.to<JsonObject>();
obj["x"] = str;
array[0] = obj["x"];
REQUIRE(str == array[0]);
}
SECTION("should not duplicate const char*") {
array[0] = "world";
const size_t expectedSize = JSON_ARRAY_SIZE(1);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate char*") {
array[0] = const_cast<char*>("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("should duplicate std::string") {
array[0] = std::string("world");
const size_t expectedSize = JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(5);
REQUIRE(expectedSize == doc.memoryUsage());
}
SECTION("array[0].to<JsonObject>()") {
JsonObject obj = array[0].to<JsonObject>();
REQUIRE(obj.isNull() == false);
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("set(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array[0].set(vla);
REQUIRE(std::string("world") == array[0]);
}
SECTION("operator=(VLA)") {
int i = 16;
char vla[i];
strcpy(vla, "world");
array.add("hello");
array[0] = vla;
REQUIRE(std::string("world") == array[0]);
}
#endif
}
TEST_CASE("JsonArrayConst::operator[]") {
DynamicJsonDocument doc(4096);
JsonArray array = doc.to<JsonArray>();
array.add(0);
SECTION("int") {
array[0] = 123;
JsonArrayConst carr = array;
REQUIRE(123 == carr[0].as<int>());
REQUIRE(true == carr[0].is<int>());
REQUIRE(false == carr[0].is<bool>());
}
}

View File

@@ -0,0 +1,35 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace Catch::Matchers;
TEST_CASE("Undefined JsonArray") {
JsonArray array;
SECTION("SubscriptFails") {
REQUIRE(array[0].isNull());
}
SECTION("AddFails") {
array.add(1);
REQUIRE(0 == array.size());
}
SECTION("CreateNestedArrayFails") {
REQUIRE(array.createNestedArray().isNull());
}
SECTION("CreateNestedObjectFails") {
REQUIRE(array.createNestedObject().isNull());
}
SECTION("PrintToWritesBrackets") {
char buffer[32];
serializeJson(array, buffer, sizeof(buffer));
REQUIRE_THAT(buffer, Equals("null"));
}
}

View File

@@ -0,0 +1,28 @@
# ArduinoJson - https://arduinojson.org
# Copyright Benoit Blanchon 2014-2021
# MIT License
add_executable(JsonDeserializerTests
array.cpp
array_static.cpp
DeserializationError.cpp
filter.cpp
incomplete_input.cpp
input_types.cpp
invalid_input.cpp
misc.cpp
nestingLimit.cpp
number.cpp
object.cpp
object_static.cpp
string.cpp
)
set_target_properties(JsonDeserializerTests PROPERTIES UNITY_BUILD OFF)
add_test(JsonDeserializer JsonDeserializerTests)
set_tests_properties(JsonDeserializer
PROPERTIES
LABELS "Catch"
)

View File

@@ -0,0 +1,130 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
void testStringification(DeserializationError error, std::string expected) {
REQUIRE(error.c_str() == expected);
}
void testBoolification(DeserializationError error, bool expected) {
// DeserializationError on left-hand side
CHECK(error == expected);
CHECK(error != !expected);
CHECK(!error == !expected);
// DeserializationError on right-hand side
CHECK(expected == error);
CHECK(!expected != error);
CHECK(!expected == !error);
}
#define TEST_STRINGIFICATION(symbol) \
testStringification(DeserializationError::symbol, #symbol)
#define TEST_BOOLIFICATION(symbol, expected) \
testBoolification(DeserializationError::symbol, expected)
TEST_CASE("DeserializationError") {
SECTION("c_str()") {
TEST_STRINGIFICATION(Ok);
TEST_STRINGIFICATION(EmptyInput);
TEST_STRINGIFICATION(IncompleteInput);
TEST_STRINGIFICATION(InvalidInput);
TEST_STRINGIFICATION(NoMemory);
TEST_STRINGIFICATION(TooDeep);
}
SECTION("as boolean") {
TEST_BOOLIFICATION(Ok, false);
TEST_BOOLIFICATION(EmptyInput, true);
TEST_BOOLIFICATION(IncompleteInput, true);
TEST_BOOLIFICATION(InvalidInput, true);
TEST_BOOLIFICATION(NoMemory, true);
TEST_BOOLIFICATION(TooDeep, true);
}
SECTION("ostream DeserializationError") {
std::stringstream s;
s << DeserializationError(DeserializationError::InvalidInput);
REQUIRE(s.str() == "InvalidInput");
}
SECTION("ostream DeserializationError::Code") {
std::stringstream s;
s << DeserializationError::InvalidInput;
REQUIRE(s.str() == "InvalidInput");
}
SECTION("switch") {
DeserializationError err = DeserializationError::InvalidInput;
switch (err.code()) {
case DeserializationError::InvalidInput:
SUCCEED();
break;
default:
FAIL();
break;
}
}
SECTION("Comparisons") {
DeserializationError invalidInput(DeserializationError::InvalidInput);
DeserializationError ok(DeserializationError::Ok);
SECTION("DeserializationError == bool") {
REQUIRE(invalidInput == true);
REQUIRE(ok == false);
}
SECTION("bool == DeserializationError") {
REQUIRE(true == invalidInput);
REQUIRE(false == ok);
}
SECTION("DeserializationError != bool") {
REQUIRE(invalidInput != false);
REQUIRE(ok != true);
}
SECTION("bool != DeserializationError") {
REQUIRE(false != invalidInput);
REQUIRE(true != ok);
}
SECTION("Negations") {
REQUIRE(!invalidInput == false);
REQUIRE(!ok == true);
}
SECTION("DeserializationError == Code") {
REQUIRE(invalidInput == DeserializationError::InvalidInput);
REQUIRE(ok == DeserializationError::Ok);
}
SECTION("Code == DeserializationError") {
REQUIRE(DeserializationError::InvalidInput == invalidInput);
REQUIRE(DeserializationError::Ok == ok);
}
SECTION("DeserializationError != Code") {
REQUIRE(invalidInput != DeserializationError::Ok);
REQUIRE(ok != DeserializationError::InvalidInput);
}
SECTION("Code != DeserializationError") {
REQUIRE(DeserializationError::Ok != invalidInput);
REQUIRE(DeserializationError::InvalidInput != ok);
}
SECTION("DeserializationError == DeserializationError") {
REQUIRE_FALSE(invalidInput == ok);
}
SECTION("DeserializationError != DeserializationError") {
REQUIRE(invalidInput != ok);
}
}
}

View File

@@ -0,0 +1,253 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserialize JSON array") {
DynamicJsonDocument doc(4096);
SECTION("An empty array") {
DeserializationError err = deserializeJson(doc, "[]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(0 == arr.size());
}
SECTION("Spaces") {
SECTION("Before the opening bracket") {
DeserializationError err = deserializeJson(doc, " []");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(0 == arr.size());
}
SECTION("Before first value") {
DeserializationError err = deserializeJson(doc, "[ \t\r\n42]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(arr[0] == 42);
}
SECTION("After first value") {
DeserializationError err = deserializeJson(doc, "[42 \t\r\n]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(arr[0] == 42);
}
}
SECTION("Values types") {
SECTION("On integer") {
DeserializationError err = deserializeJson(doc, "[42]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(arr[0] == 42);
}
SECTION("Two integers") {
DeserializationError err = deserializeJson(doc, "[42,84]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == 42);
REQUIRE(arr[1] == 84);
}
SECTION("Double") {
DeserializationError err = deserializeJson(doc, "[4.2,1e2]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == 4.2);
REQUIRE(arr[1] == 1e2);
}
SECTION("Unsigned long") {
DeserializationError err = deserializeJson(doc, "[4294967295]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(arr[0] == 4294967295UL);
}
SECTION("Boolean") {
DeserializationError err = deserializeJson(doc, "[true,false]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == true);
REQUIRE(arr[1] == false);
}
SECTION("Null") {
DeserializationError err = deserializeJson(doc, "[null,null]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0].as<const char*>() == 0);
REQUIRE(arr[1].as<const char*>() == 0);
}
}
SECTION("Quotes") {
SECTION("Double quotes") {
DeserializationError err =
deserializeJson(doc, "[ \"hello\" , \"world\" ]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == "hello");
REQUIRE(arr[1] == "world");
}
SECTION("Single quotes") {
DeserializationError err = deserializeJson(doc, "[ 'hello' , 'world' ]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == "hello");
REQUIRE(arr[1] == "world");
}
SECTION("No quotes") {
DeserializationError err = deserializeJson(doc, "[ hello , world ]");
REQUIRE(err == DeserializationError::InvalidInput);
}
SECTION("Double quotes (empty strings)") {
DeserializationError err = deserializeJson(doc, "[\"\",\"\"]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == "");
REQUIRE(arr[1] == "");
}
SECTION("Single quotes (empty strings)") {
DeserializationError err = deserializeJson(doc, "[\'\',\'\']");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(2 == arr.size());
REQUIRE(arr[0] == "");
REQUIRE(arr[1] == "");
}
SECTION("No quotes (empty strings)") {
DeserializationError err = deserializeJson(doc, "[,]");
REQUIRE(err == DeserializationError::InvalidInput);
}
SECTION("Closing single quotes missing") {
DeserializationError err = deserializeJson(doc, "[\"]");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("Closing double quotes missing") {
DeserializationError err = deserializeJson(doc, "[\']");
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
SECTION("Premature null-terminator") {
SECTION("After opening bracket") {
DeserializationError err = deserializeJson(doc, "[");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("After value") {
DeserializationError err = deserializeJson(doc, "[1");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("After comma") {
DeserializationError err = deserializeJson(doc, "[1,");
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
SECTION("Premature end of input") {
const char* input = "[1,2]";
SECTION("After opening bracket") {
DeserializationError err = deserializeJson(doc, input, 1);
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("After value") {
DeserializationError err = deserializeJson(doc, input, 2);
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("After comma") {
DeserializationError err = deserializeJson(doc, input, 3);
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
SECTION("Misc") {
SECTION("Nested objects") {
char jsonString[] =
" [ { \"a\" : 1 , \"b\" : 2 } , { \"c\" : 3 , \"d\" : 4 } ] ";
DeserializationError err = deserializeJson(doc, jsonString);
JsonArray arr = doc.as<JsonArray>();
JsonObject object1 = arr[0];
const JsonObject object2 = arr[1];
JsonObject object3 = arr[2];
REQUIRE(err == DeserializationError::Ok);
REQUIRE(object1.isNull() == false);
REQUIRE(object2.isNull() == false);
REQUIRE(object3.isNull() == true);
REQUIRE(2 == object1.size());
REQUIRE(2 == object2.size());
REQUIRE(0 == object3.size());
REQUIRE(1 == object1["a"].as<int>());
REQUIRE(2 == object1["b"].as<int>());
REQUIRE(3 == object2["c"].as<int>());
REQUIRE(4 == object2["d"].as<int>());
REQUIRE(0 == object3["e"].as<int>());
}
}
SECTION("Should clear the JsonArray") {
deserializeJson(doc, "[1,2,3,4]");
deserializeJson(doc, "[]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr.size() == 0);
REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(0));
}
}

View File

@@ -0,0 +1,89 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("deserialize JSON array with a StaticJsonDocument") {
SECTION("BufferOfTheRightSizeForEmptyArray") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
char input[] = "[]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("TooSmallBufferForArrayWithOneValue") {
StaticJsonDocument<JSON_ARRAY_SIZE(0)> doc;
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithOneValue") {
StaticJsonDocument<JSON_ARRAY_SIZE(1)> doc;
char input[] = "[1]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("TooSmallBufferForArrayWithNestedObject") {
StaticJsonDocument<JSON_ARRAY_SIZE(0) + JSON_OBJECT_SIZE(0)> doc;
char input[] = "[{}]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::NoMemory);
}
SECTION("BufferOfTheRightSizeForArrayWithNestedObject") {
StaticJsonDocument<JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(0)> doc;
char input[] = "[{}]";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("CopyStringNotSpaces") {
StaticJsonDocument<100> doc;
deserializeJson(doc, " [ \"1234567\" ] ");
REQUIRE(JSON_ARRAY_SIZE(1) + JSON_STRING_SIZE(7) == doc.memoryUsage());
// note: we use a string of 8 bytes to be sure that the StaticMemoryPool
// will not insert bytes to enforce alignement
}
SECTION("Should clear the JsonArray") {
StaticJsonDocument<JSON_ARRAY_SIZE(4)> doc;
char input[] = "[1,2,3,4]";
deserializeJson(doc, input);
deserializeJson(doc, "[]");
JsonArray arr = doc.as<JsonArray>();
REQUIRE(arr.size() == 0);
REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(0));
}
SECTION("Array") {
StaticJsonDocument<JSON_ARRAY_SIZE(2)> doc;
char input[] = "[1,2]";
DeserializationError err = deserializeJson(doc, input);
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<JsonArray>());
REQUIRE(doc.memoryUsage() == JSON_ARRAY_SIZE(2));
REQUIRE(arr[0] == 1);
REQUIRE(arr[1] == 2);
}
}

View File

@@ -0,0 +1,750 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#define ARDUINOJSON_ENABLE_COMMENTS 1
#include <ArduinoJson.h>
#include <catch.hpp>
#include <sstream>
#include <string>
TEST_CASE("Filtering") {
struct TestCase {
const char* input;
const char* filter;
uint8_t nestingLimit;
DeserializationError error;
const char* output;
size_t memoryUsage;
};
// clang-format off
TestCase testCases[] = {
{
"{\"hello\":\"world\"}", // 1. input
"null", // 2. filter
10, // 3. nestingLimit
DeserializationError::Ok, // 4. error
"null", // 5. output
0 // 6. memoryUsage
},
{
"{\"hello\":\"world\"}",
"false",
10,
DeserializationError::Ok,
"null",
0
},
{
"{\"abcdefg\":\"hijklmn\"}",
"true",
10,
DeserializationError::Ok,
"{\"abcdefg\":\"hijklmn\"}",
JSON_OBJECT_SIZE(1) + 16
},
{
"{\"hello\":\"world\"}",
"{}",
10,
DeserializationError::Ok,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// Input in an object, but filter wants an array
"{\"hello\":\"world\"}",
"[]",
10,
DeserializationError::Ok,
"null",
0
},
{
// Member is a string, but filter wants an array
"{\"example\":\"example\"}",
"{\"example\":[true]}",
10,
DeserializationError::Ok,
"{\"example\":null}",
JSON_OBJECT_SIZE(1) + 8
},
{
// Input is an array, but filter wants an object
"[\"hello\",\"world\"]",
"{}",
10,
DeserializationError::Ok,
"null",
0
},
{
// Input is a bool, but filter wants an object
"true",
"{}",
10,
DeserializationError::Ok,
"null",
0
},
{
// Input is a string, but filter wants an object
"\"hello\"",
"{}",
10,
DeserializationError::Ok,
"null",
0
},
{
// skip an integer
"{\"an_integer\":666,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// skip a float
"{\"a_float\":12.34e-6,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip a boolean
"{\"a_bool\":false,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip a double-quoted string
"{\"a_double_quoted_string\":\"hello\",example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip a single-quoted string
"{\"a_single_quoted_string\":'hello',example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an empty array
"{\"an_empty_array\":[],example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an empty array with spaces in it
"{\"an_empty_array\":[\t],example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an array
"{\"an_array\":[1,2,3],example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an array with spaces in it
"{\"an_array\": [ 1 , 2 , 3 ] ,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an empty object
"{\"an_empty_object\":{},example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an empty object with spaces in it
"{\"an_empty_object\":{ },example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// can skip an object
"{\"an_object\":{a:1,'b':2,\"c\":3},example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
// skip an object with spaces in it
"{\"an_object\" : { a : 1 , 'b' : 2 , \"c\" : 3 } ,example:42}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{\"example\":42}",
JSON_OBJECT_SIZE(1) + 8
},
{
"{\"an_integer\": 0,\"example\":{\"type\":\"int\",\"outcome\":42}}",
"{\"example\":{\"outcome\":true}}",
10,
DeserializationError::Ok,
"{\"example\":{\"outcome\":42}}",
2 * JSON_OBJECT_SIZE(1) + 16
},
{
// wildcard
"{\"example\":{\"type\":\"int\",\"outcome\":42}}",
"{\"*\":{\"outcome\":true}}",
10,
DeserializationError::Ok,
"{\"example\":{\"outcome\":42}}",
2 * JSON_OBJECT_SIZE(1) + 16
},
{
// only the first element of array counts
"[1,2,3]",
"[true, false]",
10,
DeserializationError::Ok,
"[1,2,3]",
JSON_ARRAY_SIZE(3)
},
{
// only the first element of array counts
"[1,2,3]",
"[false, true]",
10,
DeserializationError::Ok,
"[]",
JSON_ARRAY_SIZE(0)
},
{
// filter members of object in array
"[{\"example\":1,\"ignore\":2},{\"example\":3,\"ignore\":4}]",
"[{\"example\":true}]",
10,
DeserializationError::Ok,
"[{\"example\":1},{\"example\":3}]",
JSON_ARRAY_SIZE(2) + 2 * JSON_OBJECT_SIZE(1) + 8
},
{
"[',2,3]",
"[false,true]",
10,
DeserializationError::IncompleteInput,
"[]",
JSON_ARRAY_SIZE(0)
},
{
"[\",2,3]",
"[false,true]",
10,
DeserializationError::IncompleteInput,
"[]",
JSON_ARRAY_SIZE(0)
},
{
// detect errors in skipped value
"[!,2,\\]",
"[false]",
10,
DeserializationError::InvalidInput,
"[]",
JSON_ARRAY_SIZE(0)
},
{
// detect incomplete string event if it's skipped
"\"ABC",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// detect incomplete string event if it's skipped
"'ABC",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// handle escaped quotes
"'A\\'BC'",
"false",
10,
DeserializationError::Ok,
"null",
0
},
{
// handle escaped quotes
"\"A\\\"BC\"",
"false",
10,
DeserializationError::Ok,
"null",
0
},
{
// detect incomplete string in presence of escaped quotes
"'A\\'BC",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// detect incomplete string in presence of escaped quotes
"\"A\\\"BC",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// skip empty array
"[]",
"false",
10,
DeserializationError::Ok,
"null",
0
},
{
// skip empty array with spaces
" [ ] ",
"false",
10,
DeserializationError::Ok,
"null",
0
},
{
// bubble up element error even if array is skipped
"[1,'2,3]",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// bubble up member error even if object is skipped
"{'hello':'worl}",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// bubble up colon error even if object is skipped
"{'hello','world'}",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// bubble up key error even if object is skipped
"{'hello:1}",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// detect invalid value in skipped object
"{'hello':!}",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// ignore invalid value in skipped object
"{'hello':\\}",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// check nesting limit even for ignored objects
"{}",
"false",
0,
DeserializationError::TooDeep,
"null",
0
},
{
// check nesting limit even for ignored objects
"{'hello':{}}",
"false",
1,
DeserializationError::TooDeep,
"null",
0
},
{
// check nesting limit even for ignored values in objects
"{'hello':{}}",
"{}",
1,
DeserializationError::TooDeep,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// check nesting limit even for ignored arrays
"[]",
"false",
0,
DeserializationError::TooDeep,
"null",
0
},
{
// check nesting limit even for ignored arrays
"[[]]",
"false",
1,
DeserializationError::TooDeep,
"null",
0
},
{
// check nesting limit even for ignored values in arrays
"[[]]",
"[]",
1,
DeserializationError::TooDeep,
"[]",
JSON_ARRAY_SIZE(0)
},
{
// supports back-slash at the end of skipped string
"\"hell\\",
"false",
1,
DeserializationError::IncompleteInput,
"null",
0
},
{
// invalid comment at after an element in a skipped array
"[1/]",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// incomplete comment at after an element in a skipped array
"[1/*]",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// missing comma in a skipped array
"[1 2]",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// invalid comment at the beginning of array
"[/1]",
"[false]",
10,
DeserializationError::InvalidInput,
"[]",
JSON_ARRAY_SIZE(0)
},
{
// incomplete comment at the begining of an array
"[/*]",
"[false]",
10,
DeserializationError::IncompleteInput,
"[]",
JSON_ARRAY_SIZE(0)
},
{
// invalid comment before key
"{/1:2}",
"{}",
10,
DeserializationError::InvalidInput,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// incomplete comment before key
"{/*:2}",
"{}",
10,
DeserializationError::IncompleteInput,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// invalid comment after key
"{\"example\"/1:2}",
"{}",
10,
DeserializationError::InvalidInput,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// incomplete comment after key
"{\"example\"/*:2}",
"{}",
10,
DeserializationError::IncompleteInput,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// invalid comment after colon
"{\"example\":/12}",
"{}",
10,
DeserializationError::InvalidInput,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// incomplete comment after colon
"{\"example\":/*2}",
"{}",
10,
DeserializationError::IncompleteInput,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// comment next to an integer
"{\"ignore\":1//,\"example\":2\n}",
"{\"example\":true}",
10,
DeserializationError::Ok,
"{}",
JSON_OBJECT_SIZE(0)
},
{
// invalid comment after opening brace of a skipped object
"{/1:2}",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// incomplete after opening brace of a skipped object
"{/*:2}",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// invalid comment after key of a skipped object
"{\"example\"/:2}",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// incomplete after after key of a skipped object
"{\"example\"/*:2}",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
{
// invalid comment after value in a skipped object
"{\"example\":2/}",
"false",
10,
DeserializationError::InvalidInput,
"null",
0
},
{
// incomplete after after value of a skipped object
"{\"example\":2/*}",
"false",
10,
DeserializationError::IncompleteInput,
"null",
0
},
}; // clang-format on
for (size_t i = 0; i < sizeof(testCases) / sizeof(testCases[0]); i++) {
CAPTURE(i);
DynamicJsonDocument filter(256);
DynamicJsonDocument doc(256);
TestCase& tc = testCases[i];
CAPTURE(tc.filter);
REQUIRE(deserializeJson(filter, tc.filter) == DeserializationError::Ok);
CAPTURE(tc.input);
CAPTURE(tc.nestingLimit);
CHECK(deserializeJson(doc, tc.input, DeserializationOption::Filter(filter),
DeserializationOption::NestingLimit(
tc.nestingLimit)) == tc.error);
CHECK(doc.as<std::string>() == tc.output);
CHECK(doc.memoryUsage() == tc.memoryUsage);
}
}
TEST_CASE("Overloads") {
StaticJsonDocument<256> doc;
StaticJsonDocument<256> filter;
using namespace DeserializationOption;
// deserializeJson(..., Filter)
SECTION("const char*, Filter") {
deserializeJson(doc, "{}", Filter(filter));
}
SECTION("const char*, size_t, Filter") {
deserializeJson(doc, "{}", 2, Filter(filter));
}
SECTION("const std::string&, Filter") {
deserializeJson(doc, std::string("{}"), Filter(filter));
}
SECTION("std::istream&, Filter") {
std::stringstream s("{}");
deserializeJson(doc, s, Filter(filter));
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("char[n], Filter") {
int i = 4;
char vla[i];
strcpy(vla, "{}");
deserializeJson(doc, vla, Filter(filter));
}
#endif
// deserializeJson(..., Filter, NestingLimit)
SECTION("const char*, Filter, NestingLimit") {
deserializeJson(doc, "{}", Filter(filter), NestingLimit(5));
}
SECTION("const char*, size_t, Filter, NestingLimit") {
deserializeJson(doc, "{}", 2, Filter(filter), NestingLimit(5));
}
SECTION("const std::string&, Filter, NestingLimit") {
deserializeJson(doc, std::string("{}"), Filter(filter), NestingLimit(5));
}
SECTION("std::istream&, Filter, NestingLimit") {
std::stringstream s("{}");
deserializeJson(doc, s, Filter(filter), NestingLimit(5));
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("char[n], Filter, NestingLimit") {
int i = 4;
char vla[i];
strcpy(vla, "{}");
deserializeJson(doc, vla, Filter(filter), NestingLimit(5));
}
#endif
// deserializeJson(..., NestingLimit, Filter)
SECTION("const char*, NestingLimit, Filter") {
deserializeJson(doc, "{}", NestingLimit(5), Filter(filter));
}
SECTION("const char*, size_t, NestingLimit, Filter") {
deserializeJson(doc, "{}", 2, NestingLimit(5), Filter(filter));
}
SECTION("const std::string&, NestingLimit, Filter") {
deserializeJson(doc, std::string("{}"), NestingLimit(5), Filter(filter));
}
SECTION("std::istream&, NestingLimit, Filter") {
std::stringstream s("{}");
deserializeJson(doc, s, NestingLimit(5), Filter(filter));
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
SECTION("char[n], NestingLimit, Filter") {
int i = 4;
char vla[i];
strcpy(vla, "{}");
deserializeJson(doc, vla, NestingLimit(5), Filter(filter));
}
#endif
}

View File

@@ -0,0 +1,29 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Truncated JSON input") {
const char* testCases[] = {"\"hello", "\'hello", "'\\u", "'\\u00", "'\\u000",
// false
"f", "fa", "fal", "fals",
// true
"t", "tr", "tru",
// null
"n", "nu", "nul",
// object
"{", "{a", "{a:", "{a:1", "{a:1,", "{a:1,"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
CAPTURE(input);
REQUIRE(deserializeJson(doc, input) ==
DeserializationError::IncompleteInput);
}
}

View File

@@ -0,0 +1,198 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#include <sstream>
#include "CustomReader.hpp"
TEST_CASE("deserializeJson(char*)") {
StaticJsonDocument<1024> doc;
SECTION("should not duplicate strings") {
char input[] = "{\"hello\":\"world\"}";
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
CHECK(doc.memoryUsage() == JSON_OBJECT_SIZE(1));
CHECK(doc.as<JsonVariant>().memoryUsage() ==
JSON_OBJECT_SIZE(1)); // issue #1318
}
}
TEST_CASE("deserializeJson(const std::string&)") {
DynamicJsonDocument doc(4096);
SECTION("should accept const string") {
const std::string input("[42]");
DeserializationError err = deserializeJson(doc, input);
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should accept temporary string") {
DeserializationError err = deserializeJson(doc, std::string("[42]"));
REQUIRE(err == DeserializationError::Ok);
}
SECTION("should duplicate content") {
std::string input("[\"hello\"]");
DeserializationError err = deserializeJson(doc, input);
input[2] = 'X'; // alter the string tomake sure we made a copy
JsonArray array = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(std::string("hello") == array[0]);
}
}
TEST_CASE("deserializeJson(std::istream&)") {
DynamicJsonDocument doc(4096);
SECTION("array") {
std::istringstream json(" [ 42 ] ");
DeserializationError err = deserializeJson(doc, json);
JsonArray arr = doc.as<JsonArray>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == arr.size());
REQUIRE(42 == arr[0]);
}
SECTION("object") {
std::istringstream json(" { hello : 'world' }");
DeserializationError err = deserializeJson(doc, json);
JsonObject obj = doc.as<JsonObject>();
REQUIRE(err == DeserializationError::Ok);
REQUIRE(1 == obj.size());
REQUIRE(std::string("world") == obj["hello"]);
}
SECTION("Should not read after the closing brace of an empty object") {
std::istringstream json("{}123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing brace") {
std::istringstream json("{\"hello\":\"world\"}123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing bracket of an empty array") {
std::istringstream json("[]123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing bracket") {
std::istringstream json("[\"hello\",\"world\"]123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
SECTION("Should not read after the closing quote") {
std::istringstream json("\"hello\"123");
deserializeJson(doc, json);
REQUIRE('1' == char(json.get()));
}
}
#ifdef HAS_VARIABLE_LENGTH_ARRAY
TEST_CASE("deserializeJson(VLA)") {
int i = 9;
char vla[i];
strcpy(vla, "{\"a\":42}");
StaticJsonDocument<JSON_OBJECT_SIZE(1)> doc;
DeserializationError err = deserializeJson(doc, vla);
REQUIRE(err == DeserializationError::Ok);
}
#endif
TEST_CASE("deserializeJson(CustomReader)") {
DynamicJsonDocument doc(4096);
CustomReader reader("[4,2]");
DeserializationError err = deserializeJson(doc, reader);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.size() == 2);
REQUIRE(doc[0] == 4);
REQUIRE(doc[1] == 2);
}
TEST_CASE("deserializeJson(JsonDocument&, MemberProxy)") {
DynamicJsonDocument doc1(4096);
doc1["payload"] = "[4,2]";
DynamicJsonDocument doc2(4096);
DeserializationError err = deserializeJson(doc2, doc1["payload"]);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc2.size() == 2);
REQUIRE(doc2[0] == 4);
REQUIRE(doc2[1] == 2);
}
TEST_CASE("deserializeJson(JsonDocument&, JsonVariant)") {
DynamicJsonDocument doc1(4096);
doc1["payload"] = "[4,2]";
DynamicJsonDocument doc2(4096);
DeserializationError err =
deserializeJson(doc2, doc1["payload"].as<JsonVariant>());
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc2.size() == 2);
REQUIRE(doc2[0] == 4);
REQUIRE(doc2[1] == 2);
}
TEST_CASE("deserializeJson(JsonDocument&, JsonVariantConst)") {
DynamicJsonDocument doc1(4096);
doc1["payload"] = "[4,2]";
DynamicJsonDocument doc2(4096);
DeserializationError err =
deserializeJson(doc2, doc1["payload"].as<JsonVariantConst>());
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc2.size() == 2);
REQUIRE(doc2[0] == 4);
REQUIRE(doc2[1] == 2);
}
TEST_CASE("deserializeJson(JsonDocument&, ElementProxy)") {
DynamicJsonDocument doc1(4096);
doc1[0] = "[4,2]";
DynamicJsonDocument doc2(4096);
DeserializationError err = deserializeJson(doc2, doc1[0]);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc2.size() == 2);
REQUIRE(doc2[0] == 4);
REQUIRE(doc2[1] == 2);
}

View File

@@ -0,0 +1,42 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#define ARDUINOJSON_DECODE_UNICODE 1
#include <ArduinoJson.h>
#include <catch.hpp>
TEST_CASE("Invalid JSON input") {
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'", "'\\u000G'",
"'\\u000/'", "\\x1234", "6a9", "1,",
"2]", "3}"};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
CAPTURE(input);
REQUIRE(deserializeJson(doc, input) == DeserializationError::InvalidInput);
}
}
TEST_CASE("Invalid JSON input that should pass") {
const char* testCases[] = {
"nulL",
"tru3",
"fals3",
"'\\ud83d'", // leading surrogate without a trailing surrogate
"'\\udda4'", // trailing surrogate without a leading surrogate
"'\\ud83d\\ud83d'", // two leading surrogates
};
const size_t testCount = sizeof(testCases) / sizeof(testCases[0]);
DynamicJsonDocument doc(4096);
for (size_t i = 0; i < testCount; i++) {
const char* input = testCases[i];
CAPTURE(input);
REQUIRE(deserializeJson(doc, input) == DeserializationError::Ok);
}
}

View File

@@ -0,0 +1,117 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
using namespace Catch::Matchers;
TEST_CASE("deserializeJson(DynamicJsonDocument&)") {
DynamicJsonDocument doc(4096);
SECTION("Edge cases") {
SECTION("null char*") {
DeserializationError err = deserializeJson(doc, static_cast<char*>(0));
REQUIRE(err != DeserializationError::Ok);
}
SECTION("null const char*") {
DeserializationError err =
deserializeJson(doc, static_cast<const char*>(0));
REQUIRE(err != DeserializationError::Ok);
}
SECTION("Empty input") {
DeserializationError err = deserializeJson(doc, "");
REQUIRE(err == DeserializationError::EmptyInput);
}
SECTION("Only spaces") {
DeserializationError err = deserializeJson(doc, " \t\n\r");
REQUIRE(err == DeserializationError::EmptyInput);
}
SECTION("issue #628") {
DeserializationError err = deserializeJson(doc, "null");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == false);
}
SECTION("Garbage") {
DeserializationError err = deserializeJson(doc, "%*$£¤");
REQUIRE(err == DeserializationError::InvalidInput);
}
}
SECTION("Booleans") {
SECTION("True") {
DeserializationError err = deserializeJson(doc, "true");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<bool>());
REQUIRE(doc.as<bool>() == true);
}
SECTION("False") {
DeserializationError err = deserializeJson(doc, "false");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<bool>());
REQUIRE(doc.as<bool>() == false);
}
}
SECTION("Premature null-terminator") {
SECTION("In escape sequence") {
DeserializationError err = deserializeJson(doc, "\"\\");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In double quoted string") {
DeserializationError err = deserializeJson(doc, "\"hello");
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In single quoted string") {
DeserializationError err = deserializeJson(doc, "'hello");
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
SECTION("Premature end of input") {
SECTION("In escape sequence") {
DeserializationError err = deserializeJson(doc, "\"\\n\"", 2);
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In double quoted string") {
DeserializationError err = deserializeJson(doc, "\"hello\"", 6);
REQUIRE(err == DeserializationError::IncompleteInput);
}
SECTION("In single quoted string") {
DeserializationError err = deserializeJson(doc, "'hello'", 6);
REQUIRE(err == DeserializationError::IncompleteInput);
}
}
SECTION("Should clear the JsonVariant") {
deserializeJson(doc, "[1,2,3]");
deserializeJson(doc, "{}");
REQUIRE(doc.is<JsonObject>());
REQUIRE(doc.memoryUsage() == JSON_OBJECT_SIZE(0));
}
}

View File

@@ -0,0 +1,101 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#include <ArduinoJson.h>
#include <catch.hpp>
#define SHOULD_WORK(expression) REQUIRE(DeserializationError::Ok == expression);
#define SHOULD_FAIL(expression) \
REQUIRE(DeserializationError::TooDeep == expression);
TEST_CASE("JsonDeserializer nesting") {
DynamicJsonDocument doc(4096);
SECTION("Input = const char*") {
SECTION("limit = 0") {
DeserializationOption::NestingLimit nesting(0);
SHOULD_WORK(deserializeJson(doc, "\"toto\"", nesting));
SHOULD_WORK(deserializeJson(doc, "123", nesting));
SHOULD_WORK(deserializeJson(doc, "true", nesting));
SHOULD_FAIL(deserializeJson(doc, "[]", nesting));
SHOULD_FAIL(deserializeJson(doc, "{}", nesting));
SHOULD_FAIL(deserializeJson(doc, "[\"toto\"]", nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":1}", nesting));
}
SECTION("limit = 1") {
DeserializationOption::NestingLimit nesting(1);
SHOULD_WORK(deserializeJson(doc, "[\"toto\"]", nesting));
SHOULD_WORK(deserializeJson(doc, "{\"toto\":1}", nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":{}}", nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":[]}", nesting));
SHOULD_FAIL(deserializeJson(doc, "[[\"toto\"]]", nesting));
SHOULD_FAIL(deserializeJson(doc, "[{\"toto\":1}]", nesting));
}
}
SECTION("char* and size_t") {
SECTION("limit = 0") {
DeserializationOption::NestingLimit nesting(0);
SHOULD_WORK(deserializeJson(doc, "\"toto\"", 6, nesting));
SHOULD_WORK(deserializeJson(doc, "123", 3, nesting));
SHOULD_WORK(deserializeJson(doc, "true", 4, nesting));
SHOULD_FAIL(deserializeJson(doc, "[]", 2, nesting));
SHOULD_FAIL(deserializeJson(doc, "{}", 2, nesting));
SHOULD_FAIL(deserializeJson(doc, "[\"toto\"]", 8, nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":1}", 10, nesting));
}
SECTION("limit = 1") {
DeserializationOption::NestingLimit nesting(1);
SHOULD_WORK(deserializeJson(doc, "[\"toto\"]", 8, nesting));
SHOULD_WORK(deserializeJson(doc, "{\"toto\":1}", 10, nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":{}}", 11, nesting));
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":[]}", 11, nesting));
SHOULD_FAIL(deserializeJson(doc, "[[\"toto\"]]", 10, nesting));
SHOULD_FAIL(deserializeJson(doc, "[{\"toto\":1}]", 12, nesting));
}
}
SECTION("Input = std::string") {
SECTION("limit = 0") {
DeserializationOption::NestingLimit nesting(0);
SHOULD_WORK(deserializeJson(doc, std::string("\"toto\""), nesting));
SHOULD_WORK(deserializeJson(doc, std::string("123"), nesting));
SHOULD_WORK(deserializeJson(doc, std::string("true"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[]"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[\"toto\"]"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{\"toto\":1}"), nesting));
}
SECTION("limit = 1") {
DeserializationOption::NestingLimit nesting(1);
SHOULD_WORK(deserializeJson(doc, std::string("[\"toto\"]"), nesting));
SHOULD_WORK(deserializeJson(doc, std::string("{\"toto\":1}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{\"toto\":{}}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("{\"toto\":[]}"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[[\"toto\"]]"), nesting));
SHOULD_FAIL(deserializeJson(doc, std::string("[{\"toto\":1}]"), nesting));
}
}
SECTION("Input = std::istream") {
SECTION("limit = 0") {
DeserializationOption::NestingLimit nesting(0);
std::istringstream good("true");
std::istringstream bad("[]");
SHOULD_WORK(deserializeJson(doc, good, nesting));
SHOULD_FAIL(deserializeJson(doc, bad, nesting));
}
SECTION("limit = 1") {
DeserializationOption::NestingLimit nesting(1);
std::istringstream good("[\"toto\"]");
std::istringstream bad("{\"toto\":{}}");
SHOULD_WORK(deserializeJson(doc, good, nesting));
SHOULD_FAIL(deserializeJson(doc, bad, nesting));
}
}
}

View File

@@ -0,0 +1,133 @@
// ArduinoJson - https://arduinojson.org
// Copyright Benoit Blanchon 2014-2021
// MIT License
#define ARDUINOJSON_USE_LONG_LONG 0
#define ARDUINOJSON_ENABLE_NAN 1
#define ARDUINOJSON_ENABLE_INFINITY 1
#include <ArduinoJson.h>
#include <limits.h>
#include <catch.hpp>
namespace my {
using ARDUINOJSON_NAMESPACE::isinf;
using ARDUINOJSON_NAMESPACE::isnan;
} // namespace my
TEST_CASE("deserialize an integer") {
DynamicJsonDocument doc(4096);
SECTION("Integer") {
SECTION("0") {
DeserializationError err = deserializeJson(doc, "0");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<int>() == true);
REQUIRE(doc.as<int>() == 0);
REQUIRE(doc.as<std::string>() == "0"); // issue #808
}
SECTION("Negative") {
DeserializationError err = deserializeJson(doc, "-42");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<int>());
REQUIRE_FALSE(doc.is<bool>());
REQUIRE(doc.as<int>() == -42);
}
#if LONG_MAX == 2147483647
SECTION("LONG_MAX") {
DeserializationError err = deserializeJson(doc, "2147483647");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == true);
REQUIRE(doc.as<long>() == LONG_MAX);
}
SECTION("LONG_MAX + 1") {
DeserializationError err = deserializeJson(doc, "2147483648");
CAPTURE(LONG_MIN);
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == false);
REQUIRE(doc.is<float>() == true);
}
#endif
#if LONG_MIN == -2147483648
SECTION("LONG_MIN") {
DeserializationError err = deserializeJson(doc, "-2147483648");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == true);
REQUIRE(doc.as<long>() == LONG_MIN);
}
SECTION("LONG_MIN - 1") {
DeserializationError err = deserializeJson(doc, "-2147483649");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<long>() == false);
REQUIRE(doc.is<float>() == true);
}
#endif
#if ULONG_MAX == 4294967295
SECTION("ULONG_MAX") {
DeserializationError err = deserializeJson(doc, "4294967295");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<unsigned long>() == true);
REQUIRE(doc.as<unsigned long>() == ULONG_MAX);
REQUIRE(doc.is<long>() == false);
}
SECTION("ULONG_MAX + 1") {
DeserializationError err = deserializeJson(doc, "4294967296");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<unsigned long>() == false);
REQUIRE(doc.is<float>() == true);
}
#endif
}
SECTION("Floats") {
SECTION("Double") {
DeserializationError err = deserializeJson(doc, "-1.23e+4");
REQUIRE(err == DeserializationError::Ok);
REQUIRE_FALSE(doc.is<int>());
REQUIRE(doc.is<double>());
REQUIRE(doc.as<double>() == Approx(-1.23e+4));
}
SECTION("NaN") {
DeserializationError err = deserializeJson(doc, "NaN");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isnan(doc.as<float>()));
}
SECTION("Infinity") {
DeserializationError err = deserializeJson(doc, "Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
SECTION("+Infinity") {
DeserializationError err = deserializeJson(doc, "+Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
SECTION("-Infinity") {
DeserializationError err = deserializeJson(doc, "-Infinity");
REQUIRE(err == DeserializationError::Ok);
REQUIRE(doc.is<float>() == true);
REQUIRE(my::isinf(doc.as<float>()));
}
}
}

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