mirror of
https://github.com/bblanchon/ArduinoJson.git
synced 2025-07-26 16:57:32 +02:00
Compare commits
100 Commits
Author | SHA1 | Date | |
---|---|---|---|
f9fe8557f1 | |||
e007d71b4f | |||
67a512a923 | |||
9cf4f3871d | |||
31253dbe13 | |||
1110d62128 | |||
c6c0649d70 | |||
61ec2c4f95 | |||
0dd6231b3f | |||
20219d74f0 | |||
64cbaa6ff7 | |||
2512993617 | |||
48ee4a178b | |||
cd4b2b2463 | |||
f806a42cc2 | |||
c1a507c158 | |||
a1809d0f31 | |||
d92eee8736 | |||
dd1d96e28f | |||
3b64197869 | |||
1f7a3f3174 | |||
fd6314e132 | |||
e4e2557b76 | |||
3b6bf45b8a | |||
65ba36622c | |||
33452c1f37 | |||
ee02c0d573 | |||
0278e94fce | |||
7643dadaec | |||
c0bebe35f1 | |||
b5bcb37657 | |||
b4a5b053ca | |||
e297932a98 | |||
e682337655 | |||
4ada3f849c | |||
5dd203bca4 | |||
362201241f | |||
2be24eded8 | |||
4327f72140 | |||
f7f1b9745d | |||
cec18177b0 | |||
f2894552f2 | |||
d3721cb122 | |||
ab72bb8601 | |||
09c89dcacf | |||
a2b09bfbd2 | |||
386105be90 | |||
83516e1740 | |||
bf99aeedb1 | |||
22dd4da3af | |||
55c3b9b3a7 | |||
d83515dcda | |||
e34c27723a | |||
b23ff65b99 | |||
556785dc1e | |||
e9c87858d1 | |||
208e7a3304 | |||
45611924f3 | |||
5b88b2c1f6 | |||
e4f3fd8c91 | |||
aec642be20 | |||
5a60c55be7 | |||
f99b2d63f9 | |||
1db803bcd3 | |||
04326d2655 | |||
9e0c56acc3 | |||
60f9f7eff6 | |||
0fe202af03 | |||
c41e8cc634 | |||
d486157a9e | |||
91aad55412 | |||
98fca74f66 | |||
60fb268d9a | |||
f1899d3049 | |||
4b779a7c1d | |||
5d1aa04e21 | |||
2f6db1edb0 | |||
aeb30ef307 | |||
1c5e5db071 | |||
68a13117dc | |||
071f718473 | |||
00949f8276 | |||
2c670e0148 | |||
002b07f0c5 | |||
5f5f927693 | |||
4d074840da | |||
82de20ee14 | |||
ece4d030a8 | |||
4d5c17b5f6 | |||
18a9a5b590 | |||
cd4bf33132 | |||
2cfefe22ac | |||
0d43e51d48 | |||
ef28064317 | |||
7c62cdb264 | |||
0ab4bdd691 | |||
af8c615266 | |||
bd13375729 | |||
5f8502ce9d | |||
1404b1ef70 |
18
.devcontainer/clang11/devcontainer.json
Normal file
18
.devcontainer/clang11/devcontainer.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Clang 11",
|
||||
"image": "conanio/clang11",
|
||||
"runArgs": [
|
||||
"--name=ArduinoJson-clang11"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools"
|
||||
],
|
||||
"settings": {
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"cmake.buildDirectory": "/tmp/build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
.devcontainer/clang13/Dockerfile
Normal file
5
.devcontainer/clang13/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y cmake git clang-13 libc++-13-dev libc++abi-13-dev
|
||||
ENV CC=clang-13 CXX=clang++-13
|
20
.devcontainer/clang13/devcontainer.json
Normal file
20
.devcontainer/clang13/devcontainer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Clang 13",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"runArgs": [
|
||||
"--name=ArduinoJson-clang13"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools"
|
||||
],
|
||||
"settings": {
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"cmake.buildDirectory": "/tmp/build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
.devcontainer/clang14/Dockerfile
Normal file
5
.devcontainer/clang14/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y cmake git clang-14 libc++-14-dev libc++abi-14-dev
|
||||
ENV CC=clang-14 CXX=clang++-14
|
20
.devcontainer/clang14/devcontainer.json
Normal file
20
.devcontainer/clang14/devcontainer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Clang 14",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"runArgs": [
|
||||
"--name=ArduinoJson-clang14"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools"
|
||||
],
|
||||
"settings": {
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"cmake.buildDirectory": "/tmp/build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
.devcontainer/clang15/Dockerfile
Normal file
5
.devcontainer/clang15/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y cmake git clang-15 libc++-15-dev libc++abi-15-dev
|
||||
ENV CC=clang-15 CXX=clang++-15
|
20
.devcontainer/clang15/devcontainer.json
Normal file
20
.devcontainer/clang15/devcontainer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Clang 15",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"runArgs": [
|
||||
"--name=ArduinoJson-clang15"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools"
|
||||
],
|
||||
"settings": {
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"cmake.buildDirectory": "/tmp/build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
.devcontainer/clang16/Dockerfile
Normal file
5
.devcontainer/clang16/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y cmake git clang-16 libc++-16-dev libc++abi-16-dev
|
||||
ENV CC=clang-16 CXX=clang++-16
|
20
.devcontainer/clang16/devcontainer.json
Normal file
20
.devcontainer/clang16/devcontainer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Clang 16",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"runArgs": [
|
||||
"--name=ArduinoJson-clang16"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools"
|
||||
],
|
||||
"settings": {
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"cmake.buildDirectory": "/tmp/build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
5
.devcontainer/clang17/Dockerfile
Normal file
5
.devcontainer/clang17/Dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM ubuntu:24.04
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y cmake git clang-17 libc++-17-dev libc++abi-17-dev
|
||||
ENV CC=clang-17 CXX=clang++-17
|
20
.devcontainer/clang17/devcontainer.json
Normal file
20
.devcontainer/clang17/devcontainer.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "Clang 17",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"runArgs": [
|
||||
"--name=ArduinoJson-clang17"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-vscode.cmake-tools"
|
||||
],
|
||||
"settings": {
|
||||
"cmake.generator": "Unix Makefiles",
|
||||
"cmake.buildDirectory": "/tmp/build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
155
.github/workflows/ci.yml
vendored
155
.github/workflows/ci.yml
vendored
@ -2,15 +2,19 @@ name: Continuous Integration
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install
|
||||
run: sudo apt-get install -y clang-format
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Symlinks
|
||||
run: find * -type l -printf "::error::%p is a symlink. This is forbidden by the Arduino Library Specification." -exec false {} +
|
||||
- name: Clang-format
|
||||
@ -47,6 +51,9 @@ jobs:
|
||||
- gcc: "11"
|
||||
- gcc: "12"
|
||||
steps:
|
||||
- name: Workaround for actions/runner-images#9491
|
||||
run: sudo sysctl vm.mmap_rnd_bits=28
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 3B4FE6ACC0B21F32
|
||||
@ -55,24 +62,29 @@ jobs:
|
||||
sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ focal main universe'
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }}
|
||||
timeout-minutes: 5
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
timeout-minutes: 1
|
||||
|
||||
- name: Configure
|
||||
run: cmake -DCMAKE_BUILD_TYPE=Debug .
|
||||
env:
|
||||
CC: gcc-${{ matrix.gcc }}
|
||||
CXX: g++-${{ matrix.gcc }}
|
||||
CXXFLAGS: ${{ matrix.cxxflags }}
|
||||
timeout-minutes: 1
|
||||
|
||||
- name: Build
|
||||
run: cmake --build .
|
||||
timeout-minutes: 10
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
echo "## CTest output" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
ctest --output-on-failure -C Debug . | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
run: ctest --output-on-failure -C Debug .
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
timeout-minutes: 2
|
||||
|
||||
clang:
|
||||
name: Clang
|
||||
@ -132,7 +144,7 @@ jobs:
|
||||
if: matrix.clang == 12 # dependency is missing in Ubuntu 22.04
|
||||
run: sudo apt-get install -y libunwind-${{ matrix.clang }}-dev
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: cmake -DCMAKE_BUILD_TYPE=Debug .
|
||||
env:
|
||||
@ -144,11 +156,7 @@ jobs:
|
||||
- name: Build
|
||||
run: cmake --build .
|
||||
- name: Test
|
||||
run: |
|
||||
echo "## CTest output" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
ctest --output-on-failure -C Debug . | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
run: ctest --output-on-failure -C Debug .
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
@ -162,7 +170,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y g++-multilib gcc-avr avr-libc
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: AVR
|
||||
run: avr-g++ -std=c++11 -Isrc extras/conf_test/avr.cpp
|
||||
- name: GCC 32-bit
|
||||
@ -180,7 +188,7 @@ jobs:
|
||||
needs: [gcc, clang]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: 32-bit
|
||||
run: |
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars32.bat"
|
||||
@ -195,17 +203,20 @@ jobs:
|
||||
xcode:
|
||||
name: XCode
|
||||
needs: clang
|
||||
runs-on: macos-11
|
||||
runs-on: macos-13
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- xcode: "11.7"
|
||||
- xcode: "12.4"
|
||||
- xcode: "13.2.1"
|
||||
- xcode: "14.1"
|
||||
- xcode: "14.2"
|
||||
- xcode: "14.3.1"
|
||||
- xcode: "15.0.1"
|
||||
- xcode: "15.1"
|
||||
- xcode: "15.2"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Select XCode version
|
||||
run: sudo xcode-select --switch /Applications/Xcode_${{ matrix.xcode }}.app
|
||||
- name: Configure
|
||||
@ -227,7 +238,7 @@ jobs:
|
||||
# runs-on: ${{ matrix.os }}
|
||||
# steps:
|
||||
# - name: Checkout
|
||||
# uses: actions/checkout@v3
|
||||
# uses: actions/checkout@v4
|
||||
# - name: Configure
|
||||
# run: cmake -DCMAKE_BUILD_TYPE=Debug .
|
||||
# - name: Build
|
||||
@ -249,7 +260,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install arduino-cli
|
||||
run: curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/local/bin sh
|
||||
- name: Install core
|
||||
@ -322,14 +333,14 @@ jobs:
|
||||
conf_test: esp8266
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up cache for pip
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install PlatformIO
|
||||
@ -341,7 +352,7 @@ jobs:
|
||||
if: ${{ matrix.platform == 'nordicnrf52' }}
|
||||
run: find examples/ -name '*.ino' -exec sed -i 's/\(#include <ArduinoJson.h>\)/\1\n#include <Adafruit_TinyUSB.h>/' {} +
|
||||
- name: Set up cache for platformio
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-platformio-${{ matrix.platform }}
|
||||
@ -390,7 +401,7 @@ jobs:
|
||||
- board: argon
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Particle CLI
|
||||
run: sudo npm install -g particle-cli
|
||||
- name: Login to Particle
|
||||
@ -408,7 +419,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y g++-arm-linux-gnueabihf
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: cmake .
|
||||
env:
|
||||
@ -425,7 +436,7 @@ jobs:
|
||||
- name: Install
|
||||
run: sudo apt-get install -y lcov ninja-build
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: cmake -G Ninja -DCOVERAGE=true .
|
||||
- name: Build
|
||||
@ -439,12 +450,12 @@ jobs:
|
||||
- name: genhtml
|
||||
run: mkdir coverage && genhtml coverage_filtered.info -o coverage -t ArduinoJson
|
||||
- name: Upload HTML report
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Coverage report
|
||||
path: coverage
|
||||
- name: Upload to Coveralls
|
||||
uses: coverallsapp/github-action@master
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path-to-lcov: coverage_filtered.info
|
||||
@ -459,7 +470,7 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y valgrind ninja-build
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: cmake -G Ninja -D MEMORYCHECK_COMMAND_OPTIONS="--error-exitcode=1 --leak-check=full" .
|
||||
- name: Build
|
||||
@ -468,7 +479,7 @@ jobs:
|
||||
run: ctest --output-on-failure -LE WillFail -T memcheck
|
||||
id: memcheck
|
||||
- name: MemoryChecker.*.log
|
||||
run: cat Testing/Temporary/MemoryChecker.*.log
|
||||
run: cat Testing/Temporary/MemoryChecker.*.log > $GITHUB_STEP_SUMMARY
|
||||
if: failure()
|
||||
|
||||
clang-tidy:
|
||||
@ -479,7 +490,7 @@ jobs:
|
||||
- name: Install
|
||||
run: sudo apt-get install -y clang-tidy cmake ninja-build
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure
|
||||
run: cmake -G Ninja -DCMAKE_CXX_CLANG_TIDY="clang-tidy-10;--warnings-as-errors=*" -DCMAKE_BUILD_TYPE=Debug .
|
||||
env:
|
||||
@ -488,73 +499,51 @@ jobs:
|
||||
- name: Check
|
||||
run: cmake --build . -- -k 0
|
||||
|
||||
amalgamate-h:
|
||||
amalgamate:
|
||||
needs: gcc
|
||||
name: Amalgamate ArduinoJson.h
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Amalgamate
|
||||
id: amalgamate
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
VERSION=${GITHUB_SHA::7}
|
||||
fi
|
||||
INPUT=src/ArduinoJson.h
|
||||
OUTPUT=ArduinoJson-$VERSION.h
|
||||
extras/scripts/build-single-header.sh "$INPUT" "$OUTPUT"
|
||||
echo "filename=${OUTPUT}" >> $GITHUB_OUTPUT
|
||||
- name: Smoke test
|
||||
echo "ARDUINOJSON_H=ArduinoJson-$VERSION.h" >> $GITHUB_ENV
|
||||
echo "ARDUINOJSON_HPP=ArduinoJson-$VERSION.hpp" >> $GITHUB_ENV
|
||||
- name: Amalgamate ArduinoJson.h
|
||||
run: extras/scripts/build-single-header.sh "src/ArduinoJson.h" "$ARDUINOJSON_H"
|
||||
- name: Amalgamate ArduinoJson.hpp
|
||||
run: extras/scripts/build-single-header.sh "src/ArduinoJson.hpp" "$ARDUINOJSON_HPP"
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Single headers
|
||||
path: |
|
||||
${{ env.ARDUINOJSON_H }}
|
||||
${{ env.ARDUINOJSON_HPP }}
|
||||
- name: Smoke test ArduinoJson.h
|
||||
run: |
|
||||
g++ -x c++ - <<END
|
||||
#include "${{ steps.amalgamate.outputs.filename }}"
|
||||
#include "$ARDUINOJSON_H"
|
||||
int main() {
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, "{}");
|
||||
}
|
||||
END
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Single headers
|
||||
path: ${{ steps.amalgamate.outputs.filename }}
|
||||
|
||||
amalgamate-hpp:
|
||||
needs: gcc
|
||||
name: Amalgamate ArduinoJson.hpp
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Amalgamate
|
||||
id: amalgamate
|
||||
run: |
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
VERSION=${GITHUB_REF#refs/tags/}
|
||||
else
|
||||
VERSION=${GITHUB_SHA::7}
|
||||
fi
|
||||
INPUT=src/ArduinoJson.hpp
|
||||
OUTPUT=ArduinoJson-$VERSION.hpp
|
||||
extras/scripts/build-single-header.sh "$INPUT" "$OUTPUT"
|
||||
echo "filename=${OUTPUT}" >> $GITHUB_OUTPUT
|
||||
- name: Smoke test
|
||||
- name: Smoke test ArduinoJson.hpp
|
||||
run: |
|
||||
g++ -x c++ - <<END
|
||||
#include "${{ steps.amalgamate.outputs.filename }}"
|
||||
#include "$ARDUINOJSON_HPP"
|
||||
int main() {
|
||||
ArduinoJson::JsonDocument doc;
|
||||
deserializeJson(doc, "{}");
|
||||
}
|
||||
END
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Single headers
|
||||
path: ${{ steps.amalgamate.outputs.filename }}
|
||||
|
||||
esp-idf:
|
||||
needs: gcc
|
||||
@ -562,14 +551,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.espressif
|
||||
key: ${{ runner.os }}-esp-idf
|
||||
- name: Checkout ArduinoJson
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout ESP-IDF
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: espressif/esp-idf
|
||||
path: esp-idf
|
||||
@ -599,10 +588,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: cpp
|
||||
|
||||
@ -612,6 +601,6 @@ jobs:
|
||||
cmake --build .
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:cpp"
|
||||
|
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v4
|
||||
- uses: dessant/lock-threads@v5
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: 30
|
||||
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
echo "tag=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
echo "version=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Write release body
|
||||
id: body
|
||||
run: |
|
||||
@ -48,7 +48,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Upload component to the component registry
|
||||
uses: espressif/upload-components-ci-action@v1
|
||||
with:
|
||||
@ -63,7 +63,7 @@ jobs:
|
||||
- name: Install
|
||||
run: npm install -g particle-cli
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Login
|
||||
run: particle login --token ${{ secrets.PARTICLE_TOKEN }}
|
||||
- name: Publish
|
||||
@ -74,13 +74,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Install PlatformIO
|
||||
run: pip install platformio
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish
|
||||
run: pio pkg publish --no-interactive --no-notify
|
||||
env:
|
||||
|
58
CHANGELOG.md
58
CHANGELOG.md
@ -1,6 +1,64 @@
|
||||
ArduinoJson: change log
|
||||
=======================
|
||||
|
||||
v7.2.1 (2024-11-15)
|
||||
------
|
||||
|
||||
* Forbid `deserializeJson(JsonArray|JsonObject, ...)` (issue #2135)
|
||||
* Fix VLA support in `JsonDocument::set()`
|
||||
* Fix `operator[](variant)` ignoring NUL characters
|
||||
|
||||
v7.2.0 (2024-09-18)
|
||||
------
|
||||
|
||||
* Store object members with two slots: one for the key and one for the value
|
||||
* Store 64-bit numbers (`double` and `long long`) in an additional slot
|
||||
* Reduce the slot size (see table below)
|
||||
* Improve message when user forgets third arg of `serializeJson()` et al.
|
||||
* Set `ARDUINOJSON_USE_DOUBLE` to `0` by default on 8-bit architectures
|
||||
* Deprecate `containsKey()` in favor of `doc["key"].is<T>()`
|
||||
* Add support for escape sequence `\'` (issue #2124)
|
||||
|
||||
| Architecture | before | after |
|
||||
|--------------|----------|----------|
|
||||
| 8-bit | 8 bytes | 6 bytes |
|
||||
| 32-bit | 16 bytes | 8 bytes |
|
||||
| 64-bit | 24 bytes | 16 bytes |
|
||||
|
||||
> ### BREAKING CHANGES
|
||||
>
|
||||
> After being on the death row for years, the `containsKey()` method has finally been deprecated.
|
||||
> You should replace `doc.containsKey("key")` with `doc["key"].is<T>()`, which not only checks that the key exists but also that the value is of the expected type.
|
||||
>
|
||||
> ```cpp
|
||||
> // Before
|
||||
> if (doc.containsKey("value")) {
|
||||
> int value = doc["value"];
|
||||
> // ...
|
||||
> }
|
||||
>
|
||||
> // After
|
||||
> if (doc["value"].is<int>()) {
|
||||
> int value = doc["value"];
|
||||
> // ...
|
||||
> }
|
||||
> ```
|
||||
|
||||
v7.1.0 (2024-06-27)
|
||||
------
|
||||
|
||||
* Add `ARDUINOJSON_STRING_LENGTH_SIZE` to the namespace name
|
||||
* Add support for MsgPack binary (PR #2078 by @Sanae6)
|
||||
* Add support for MsgPack extension
|
||||
* Make string support even more generic (PR #2084 by @d-a-v)
|
||||
* Optimize `deserializeMsgPack()`
|
||||
* Allow using a `JsonVariant` as a key or index (issue #2080)
|
||||
Note: works only for reading, not for writing
|
||||
* Support `ElementProxy` and `MemberProxy` in `JsonDocument`'s constructor
|
||||
* Don't add partial objects when allocation fails (issue #2081)
|
||||
* Read MsgPack's 64-bit integers even if `ARDUINOJSON_USE_LONG_LONG` is `0`
|
||||
(they are set to `null` if they don't fit in a `long`)
|
||||
|
||||
v7.0.4 (2024-03-12)
|
||||
------
|
||||
|
||||
|
@ -10,7 +10,7 @@ if(ESP_PLATFORM)
|
||||
return()
|
||||
endif()
|
||||
|
||||
project(ArduinoJson VERSION 7.0.4)
|
||||
project(ArduinoJson VERSION 7.2.1)
|
||||
|
||||
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||
include(CTest)
|
||||
|
@ -148,6 +148,9 @@ ArduinoJson is thankful to its sponsors. Please give them a visit; they deserve
|
||||
<a href="https://github.com/1technophile" rel="sponsored">
|
||||
<img alt="1technophile" src="https://avatars.githubusercontent.com/u/12672732?s=40&v=4">
|
||||
</a>
|
||||
<a href="https://github.com/LArkema" rel="sponsored">
|
||||
<img alt="LArkema" src="https://avatars.githubusercontent.com/u/38381313?s=40&v=4">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
If you run a commercial project that embeds ArduinoJson, think about [sponsoring the library's development](https://github.com/sponsors/bblanchon): it ensures the code that your products rely on stays actively maintained. It can also give your project some exposure to the makers' community.
|
||||
|
@ -1,4 +1,4 @@
|
||||
version: 7.0.4.{build}
|
||||
version: 7.2.1.{build}
|
||||
environment:
|
||||
matrix:
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
|
@ -1,3 +1,7 @@
|
||||
if(NOT DEFINED COVERAGE)
|
||||
set(COVERAGE OFF)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
add_compile_options(
|
||||
-pedantic
|
||||
@ -30,7 +34,7 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.8) AND(NOT ${COVERAGE}))
|
||||
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9) AND(NOT ${COVERAGE}))
|
||||
add_compile_options(-g -Og)
|
||||
else() # GCC 4.8
|
||||
add_compile_options(
|
||||
|
@ -6,12 +6,13 @@ static_assert(ARDUINOJSON_USE_LONG_LONG == 0, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 1, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 16, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 0, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 8,
|
||||
"sizeof(VariantSlot)");
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 6, "slot size");
|
||||
|
||||
void setup() {}
|
||||
void loop() {}
|
||||
|
@ -4,12 +4,13 @@ static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 128, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16,
|
||||
"sizeof(VariantSlot)");
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 8, "slot size");
|
||||
|
||||
void setup() {}
|
||||
void loop() {}
|
||||
|
@ -4,11 +4,13 @@ static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 4, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 256, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 24,
|
||||
"sizeof(VariantSlot)");
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 16,
|
||||
"slot size");
|
||||
|
||||
int main() {}
|
||||
|
@ -4,11 +4,12 @@ static_assert(ARDUINOJSON_USE_LONG_LONG == 1, "ARDUINOJSON_USE_LONG_LONG");
|
||||
|
||||
static_assert(ARDUINOJSON_SLOT_ID_SIZE == 2, "ARDUINOJSON_SLOT_ID_SIZE");
|
||||
|
||||
static_assert(ARDUINOJSON_POOL_CAPACITY == 128, "ARDUINOJSON_POOL_CAPACITY");
|
||||
|
||||
static_assert(ARDUINOJSON_LITTLE_ENDIAN == 1, "ARDUINOJSON_LITTLE_ENDIAN");
|
||||
|
||||
static_assert(ARDUINOJSON_USE_DOUBLE == 1, "ARDUINOJSON_USE_DOUBLE");
|
||||
|
||||
static_assert(sizeof(ArduinoJson::detail::VariantSlot) == 16,
|
||||
"sizeof(VariantSlot)");
|
||||
static_assert(ArduinoJson::detail::ResourceManager::slotSize == 8, "slot size");
|
||||
|
||||
int main() {}
|
||||
|
@ -52,7 +52,16 @@ macro(add_fuzzer name)
|
||||
)
|
||||
endmacro()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6)
|
||||
# Needs Clang 6+ to compile
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6)
|
||||
if(DEFINED ENV{GITHUB_ACTIONS} AND CMAKE_CXX_COMPILER_VERSION MATCHES "^11\\.")
|
||||
# Clang 11 fails on GitHub Actions with the following error:
|
||||
# > ERROR: UndefinedBehaviorSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)
|
||||
# > Sanitizer CHECK failed: /build/llvm-toolchain-11-mnvtwk/llvm-toolchain-11-11.1.0/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp:54 ((0 && "unable to mmap")) != (0) (0, 0)
|
||||
message(WARNING "Fuzzing is disabled on GitHub Actions to workaround a bug in Clang 11")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_fuzzer(json)
|
||||
add_fuzzer(msgpack)
|
||||
endif()
|
||||
|
@ -5,15 +5,18 @@
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_subdirectory(catch)
|
||||
link_libraries(ArduinoJson)
|
||||
|
||||
link_libraries(ArduinoJson catch)
|
||||
# Failing builds should only link with ArduinoJson, not catch
|
||||
add_subdirectory(FailingBuilds)
|
||||
|
||||
add_subdirectory(catch)
|
||||
link_libraries(catch)
|
||||
|
||||
include_directories(Helpers)
|
||||
add_subdirectory(Cpp17)
|
||||
add_subdirectory(Cpp20)
|
||||
add_subdirectory(Deprecated)
|
||||
add_subdirectory(FailingBuilds)
|
||||
add_subdirectory(IntegrationTests)
|
||||
add_subdirectory(JsonArray)
|
||||
add_subdirectory(JsonArrayConst)
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
#if !ARDUINOJSON_ENABLE_STRING_VIEW
|
||||
# error ARDUINOJSON_ENABLE_STRING_VIEW must be set to 1
|
||||
@ -92,7 +93,7 @@ TEST_CASE("string_view") {
|
||||
}
|
||||
|
||||
SECTION("String containing NUL") {
|
||||
doc.set(std::string("hello\0world", 11));
|
||||
doc.set("hello\0world"_s);
|
||||
REQUIRE(doc.as<std::string_view>().size() == 11);
|
||||
REQUIRE(doc.as<std::string_view>() == std::string_view("hello\0world", 11));
|
||||
}
|
||||
|
@ -16,9 +16,10 @@ endif()
|
||||
|
||||
add_executable(DeprecatedTests
|
||||
add.cpp
|
||||
BasicJsonDocument.cpp
|
||||
containsKey.cpp
|
||||
createNestedArray.cpp
|
||||
createNestedObject.cpp
|
||||
BasicJsonDocument.cpp
|
||||
DynamicJsonDocument.cpp
|
||||
macros.cpp
|
||||
memoryUsage.cpp
|
||||
|
246
extras/tests/Deprecated/containsKey.cpp
Normal file
246
extras/tests/Deprecated/containsKey.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::containsKey()") {
|
||||
JsonDocument doc;
|
||||
|
||||
SECTION("returns true on object") {
|
||||
doc["hello"] = "world";
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == true);
|
||||
}
|
||||
|
||||
SECTION("returns true when value is null") {
|
||||
doc["hello"] = static_cast<const char*>(0);
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == true);
|
||||
}
|
||||
|
||||
SECTION("returns true when key is a std::string") {
|
||||
doc["hello"] = "world";
|
||||
|
||||
REQUIRE(doc.containsKey("hello"_s) == true);
|
||||
}
|
||||
|
||||
SECTION("returns false on object") {
|
||||
doc["world"] = "hello";
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
|
||||
SECTION("returns false on array") {
|
||||
doc.add("hello");
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
|
||||
SECTION("returns false on null") {
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
|
||||
SECTION("supports JsonVariant") {
|
||||
doc["hello"] = "world";
|
||||
doc["key"] = "hello";
|
||||
|
||||
REQUIRE(doc.containsKey(doc["key"]) == true);
|
||||
REQUIRE(doc.containsKey(doc["foo"]) == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
doc["hello"] = "world";
|
||||
|
||||
REQUIRE(doc.containsKey(vla) == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::containsKey()") {
|
||||
JsonDocument doc;
|
||||
auto mp = doc["hello"];
|
||||
|
||||
SECTION("containsKey(const char*)") {
|
||||
mp["key"] = "value";
|
||||
|
||||
REQUIRE(mp.containsKey("key") == true);
|
||||
REQUIRE(mp.containsKey("key") == true);
|
||||
}
|
||||
|
||||
SECTION("containsKey(std::string)") {
|
||||
mp["key"] = "value";
|
||||
|
||||
REQUIRE(mp.containsKey("key"_s) == true);
|
||||
REQUIRE(mp.containsKey("key"_s) == true);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
mp["hello"] = "world";
|
||||
|
||||
REQUIRE(mp.containsKey(vla) == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonObject::containsKey()") {
|
||||
JsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = 42;
|
||||
|
||||
SECTION("returns true only if key is present") {
|
||||
REQUIRE(false == obj.containsKey("world"));
|
||||
REQUIRE(true == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
SECTION("returns false after remove()") {
|
||||
obj.remove("hello");
|
||||
|
||||
REQUIRE(false == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == obj.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("key is a JsonVariant") {
|
||||
doc["key"] = "hello";
|
||||
REQUIRE(true == obj.containsKey(obj["key"]));
|
||||
REQUIRE(false == obj.containsKey(obj["hello"]));
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
REQUIRE(true == obj.containsKey("hello"_s));
|
||||
}
|
||||
|
||||
SECTION("unsigned char[]") {
|
||||
unsigned char key[] = "hello";
|
||||
REQUIRE(true == obj.containsKey(key));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonObjectConst::containsKey()") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = 42;
|
||||
auto obj = doc.as<JsonObjectConst>();
|
||||
|
||||
SECTION("supports const char*") {
|
||||
REQUIRE(false == obj.containsKey("world"));
|
||||
REQUIRE(true == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
SECTION("supports std::string") {
|
||||
REQUIRE(false == obj.containsKey("world"_s));
|
||||
REQUIRE(true == obj.containsKey("hello"_s));
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == obj.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("supports JsonVariant") {
|
||||
doc["key"] = "hello";
|
||||
REQUIRE(true == obj.containsKey(obj["key"]));
|
||||
REQUIRE(false == obj.containsKey(obj["hello"]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::containsKey()") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("returns false is unbound") {
|
||||
CHECK_FALSE(JsonVariant().containsKey("hello"));
|
||||
}
|
||||
|
||||
SECTION("containsKey(const char*)") {
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(var.containsKey("hello") == true);
|
||||
REQUIRE(var.containsKey("world") == false);
|
||||
}
|
||||
|
||||
SECTION("containsKey(std::string)") {
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(var.containsKey("hello"_s) == true);
|
||||
REQUIRE(var.containsKey("world"_s) == false);
|
||||
}
|
||||
|
||||
SECTION("containsKey(JsonVariant)") {
|
||||
var["hello"] = "world";
|
||||
var["key"] = "hello";
|
||||
|
||||
REQUIRE(var.containsKey(doc["key"]) == true);
|
||||
REQUIRE(var.containsKey(doc["foo"]) == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(var.containsKey(vla) == true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariantConst::containsKey()") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = "world";
|
||||
JsonVariantConst var = doc.as<JsonVariant>();
|
||||
|
||||
SECTION("support const char*") {
|
||||
REQUIRE(var.containsKey("hello") == true);
|
||||
REQUIRE(var.containsKey("world") == false);
|
||||
}
|
||||
|
||||
SECTION("support std::string") {
|
||||
REQUIRE(var.containsKey("hello"_s) == true);
|
||||
REQUIRE(var.containsKey("world"_s) == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == var.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("support JsonVariant") {
|
||||
doc["key"] = "hello";
|
||||
REQUIRE(var.containsKey(var["key"]) == true);
|
||||
REQUIRE(var.containsKey(var["foo"]) == false);
|
||||
}
|
||||
}
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::createNestedArray()") {
|
||||
JsonDocument doc;
|
||||
|
||||
@ -23,7 +25,7 @@ TEST_CASE("JsonDocument::createNestedArray()") {
|
||||
}
|
||||
|
||||
SECTION("createNestedArray(std::string)") {
|
||||
JsonArray array = doc.createNestedArray(std::string("key"));
|
||||
JsonArray array = doc.createNestedArray("key"_s);
|
||||
array.add(42);
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":[42]}");
|
||||
}
|
||||
@ -59,7 +61,7 @@ TEST_CASE("JsonObject::createNestedArray()") {
|
||||
}
|
||||
|
||||
SECTION("createNestedArray(std::string)") {
|
||||
JsonArray array = object.createNestedArray(std::string("key"));
|
||||
JsonArray array = object.createNestedArray("key"_s);
|
||||
array.add(42);
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":[42]}");
|
||||
}
|
||||
@ -93,7 +95,7 @@ TEST_CASE("JsonVariant::createNestedArray()") {
|
||||
}
|
||||
|
||||
SECTION("createNestedArray(std::string)") {
|
||||
JsonArray array = variant.createNestedArray(std::string("key"));
|
||||
JsonArray array = variant.createNestedArray("key"_s);
|
||||
array.add(42);
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":[42]}");
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::createNestedObject()") {
|
||||
JsonDocument doc;
|
||||
|
||||
@ -23,7 +25,7 @@ TEST_CASE("JsonDocument::createNestedObject()") {
|
||||
}
|
||||
|
||||
SECTION("createNestedObject(std::string)") {
|
||||
JsonObject object = doc.createNestedObject(std::string("key"));
|
||||
JsonObject object = doc.createNestedObject("key"_s);
|
||||
object["hello"] = "world";
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":{\"hello\":\"world\"}}");
|
||||
}
|
||||
@ -59,7 +61,7 @@ TEST_CASE("JsonObject::createNestedObject()") {
|
||||
}
|
||||
|
||||
SECTION("createNestedObject(std::string)") {
|
||||
JsonObject nestedObject = object.createNestedObject(std::string("key"));
|
||||
JsonObject nestedObject = object.createNestedObject("key"_s);
|
||||
nestedObject["hello"] = "world";
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":{\"hello\":\"world\"}}");
|
||||
}
|
||||
@ -93,7 +95,7 @@ TEST_CASE("JsonVariant::createNestedObject()") {
|
||||
}
|
||||
|
||||
SECTION("createNestedObject(std::string)") {
|
||||
JsonObject object = variant.createNestedObject(std::string("key"));
|
||||
JsonObject object = variant.createNestedObject("key"_s);
|
||||
object["hello"] = "world";
|
||||
REQUIRE(doc.as<std::string>() == "{\"key\":{\"hello\":\"world\"}}");
|
||||
}
|
||||
|
@ -2,7 +2,11 @@
|
||||
# Copyright © 2014-2024, Benoit BLANCHON
|
||||
# MIT License
|
||||
|
||||
macro(build_should_fail target)
|
||||
macro(add_failing_build source_file)
|
||||
get_filename_component(target ${source_file} NAME_WE)
|
||||
|
||||
add_executable(${target} ${source_file})
|
||||
|
||||
set_target_properties(${target}
|
||||
PROPERTIES
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
@ -16,21 +20,13 @@ macro(build_should_fail target)
|
||||
set_tests_properties(${target}
|
||||
PROPERTIES
|
||||
WILL_FAIL TRUE
|
||||
LABELS "WillFail;Catch"
|
||||
LABELS "WillFail"
|
||||
)
|
||||
endmacro()
|
||||
|
||||
add_executable(Issue978 Issue978.cpp)
|
||||
build_should_fail(Issue978)
|
||||
|
||||
add_executable(read_long_long read_long_long.cpp)
|
||||
build_should_fail(read_long_long)
|
||||
|
||||
add_executable(write_long_long write_long_long.cpp)
|
||||
build_should_fail(write_long_long)
|
||||
|
||||
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)
|
||||
add_failing_build(Issue978.cpp)
|
||||
add_failing_build(read_long_long.cpp)
|
||||
add_failing_build(write_long_long.cpp)
|
||||
add_failing_build(variant_as_char.cpp)
|
||||
add_failing_build(assign_char.cpp)
|
||||
add_failing_build(deserialize_object.cpp)
|
||||
|
12
extras/tests/FailingBuilds/deserialize_object.cpp
Normal file
12
extras/tests/FailingBuilds/deserialize_object.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
// See issue #2135
|
||||
|
||||
int main() {
|
||||
JsonObject obj;
|
||||
deserializeJson(obj, "");
|
||||
}
|
@ -5,11 +5,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <ArduinoJson/Memory/Allocator.hpp>
|
||||
#include <ArduinoJson/Memory/MemoryPool.hpp>
|
||||
#include <ArduinoJson/Memory/StringBuilder.hpp>
|
||||
#include <ArduinoJson/Memory/VariantPool.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace {
|
||||
|
||||
struct FailingAllocator : ArduinoJson::Allocator {
|
||||
static FailingAllocator* instance() {
|
||||
static FailingAllocator allocator;
|
||||
@ -54,31 +56,31 @@ class AllocatorLogEntry {
|
||||
|
||||
inline AllocatorLogEntry Allocate(size_t s) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "allocate(%zu)", s);
|
||||
snprintf(buffer, sizeof(buffer), "allocate(%zu)", s);
|
||||
return AllocatorLogEntry(buffer);
|
||||
}
|
||||
|
||||
inline AllocatorLogEntry AllocateFail(size_t s) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "allocate(%zu) -> nullptr", s);
|
||||
snprintf(buffer, sizeof(buffer), "allocate(%zu) -> nullptr", s);
|
||||
return AllocatorLogEntry(buffer);
|
||||
}
|
||||
|
||||
inline AllocatorLogEntry Reallocate(size_t s1, size_t s2) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "reallocate(%zu, %zu)", s1, s2);
|
||||
snprintf(buffer, sizeof(buffer), "reallocate(%zu, %zu)", s1, s2);
|
||||
return AllocatorLogEntry(buffer);
|
||||
}
|
||||
|
||||
inline AllocatorLogEntry ReallocateFail(size_t s1, size_t s2) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "reallocate(%zu, %zu) -> nullptr", s1, s2);
|
||||
snprintf(buffer, sizeof(buffer), "reallocate(%zu, %zu) -> nullptr", s1, s2);
|
||||
return AllocatorLogEntry(buffer);
|
||||
}
|
||||
|
||||
inline AllocatorLogEntry Deallocate(size_t s) {
|
||||
char buffer[32];
|
||||
sprintf(buffer, "deallocate(%zu)", s);
|
||||
snprintf(buffer, sizeof(buffer), "deallocate(%zu)", s);
|
||||
return AllocatorLogEntry(buffer);
|
||||
}
|
||||
|
||||
@ -260,14 +262,17 @@ class TimebombAllocator : public ArduinoJson::Allocator {
|
||||
size_t countdown_ = 0;
|
||||
Allocator* upstream_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
inline size_t sizeofPoolList(size_t n = ARDUINOJSON_INITIAL_POOL_COUNT) {
|
||||
return sizeof(ArduinoJson::detail::VariantPool) * n;
|
||||
using namespace ArduinoJson::detail;
|
||||
return sizeof(MemoryPool<VariantData>) * n;
|
||||
}
|
||||
|
||||
inline size_t sizeofPool(
|
||||
ArduinoJson::detail::SlotCount n = ARDUINOJSON_POOL_CAPACITY) {
|
||||
return ArduinoJson::detail::VariantPool::slotsToBytes(n);
|
||||
using namespace ArduinoJson::detail;
|
||||
return MemoryPool<VariantData>::slotsToBytes(n);
|
||||
}
|
||||
|
||||
inline size_t sizeofStringBuffer(size_t iteration = 1) {
|
||||
|
12
extras/tests/Helpers/Literals.hpp
Normal file
12
extras/tests/Helpers/Literals.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
// the space before _s is required by GCC 4.8
|
||||
inline std::string operator"" _s(const char* str, size_t len) {
|
||||
return std::string(str, len);
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
|
||||
@ -51,7 +52,7 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
|
||||
array.add(vla);
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -115,7 +116,7 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
array.add(std::string("world"));
|
||||
array.add("world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
@ -139,7 +140,7 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(std::string)") {
|
||||
array.add(serialized(std::string("{}")));
|
||||
array.add(serialized("{}"_s));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("{}")),
|
||||
@ -147,7 +148,7 @@ TEST_CASE("JsonArray::add(T)") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate serialized(std::string)") {
|
||||
array.add(serialized(std::string("\0XX", 3)));
|
||||
array.add(serialized("\0XX"_s));
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString(" XX")),
|
||||
@ -179,3 +180,52 @@ TEST_CASE("JsonArray::add<T>()") {
|
||||
REQUIRE(doc.as<std::string>() == "[42]");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonObject::add(JsonObject) ") {
|
||||
JsonDocument doc1;
|
||||
doc1["key1"_s] = "value1"_s;
|
||||
|
||||
TimebombAllocator allocator(10);
|
||||
SpyingAllocator spy(&allocator);
|
||||
JsonDocument doc2(&spy);
|
||||
JsonArray array = doc2.to<JsonArray>();
|
||||
|
||||
SECTION("success") {
|
||||
bool result = array.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc2.as<std::string>() == "[{\"key1\":\"value1\"}]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("key1")),
|
||||
Allocate(sizeofString("value1")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("partial failure") { // issue #2081
|
||||
allocator.setCountdown(2);
|
||||
|
||||
bool result = array.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc2.as<std::string>() == "[]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("key1")),
|
||||
AllocateFail(sizeofString("value1")),
|
||||
Deallocate(sizeofString("key1")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("complete failure") {
|
||||
allocator.setCountdown(0);
|
||||
|
||||
bool result = array.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc2.as<std::string>() == "[]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
AllocateFail(sizeofPool()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("copyArray()") {
|
||||
SECTION("int[] -> JsonArray") {
|
||||
@ -18,7 +19,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(array, json);
|
||||
CHECK(std::string("[1,2,3]") == json);
|
||||
CHECK("[1,2,3]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("std::string[] -> JsonArray") {
|
||||
@ -31,7 +32,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(array, json);
|
||||
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
|
||||
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("const char*[] -> JsonArray") {
|
||||
@ -44,7 +45,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(array, json);
|
||||
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
|
||||
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("const char[][] -> JsonArray") {
|
||||
@ -57,7 +58,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(array, json);
|
||||
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
|
||||
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("const char[][] -> JsonDocument") {
|
||||
@ -69,7 +70,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(doc, json);
|
||||
CHECK(std::string("[\"a\",\"b\",\"c\"]") == json);
|
||||
CHECK("[\"a\",\"b\",\"c\"]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("const char[][] -> MemberProxy") {
|
||||
@ -81,7 +82,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(doc, json);
|
||||
CHECK(std::string("{\"data\":[\"a\",\"b\",\"c\"]}") == json);
|
||||
CHECK("{\"data\":[\"a\",\"b\",\"c\"]}"_s == json);
|
||||
}
|
||||
|
||||
SECTION("int[] -> JsonDocument") {
|
||||
@ -93,7 +94,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(doc, json);
|
||||
CHECK(std::string("[1,2,3]") == json);
|
||||
CHECK("[1,2,3]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("int[] -> MemberProxy") {
|
||||
@ -105,7 +106,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(doc, json);
|
||||
CHECK(std::string("{\"data\":[1,2,3]}") == json);
|
||||
CHECK("{\"data\":[1,2,3]}"_s == json);
|
||||
}
|
||||
|
||||
SECTION("int[] -> JsonArray, but not enough memory") {
|
||||
@ -127,7 +128,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(array, json);
|
||||
CHECK(std::string("[[1,2,3],[4,5,6]]") == json);
|
||||
CHECK("[[1,2,3],[4,5,6]]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("int[][] -> MemberProxy") {
|
||||
@ -139,7 +140,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(doc, json);
|
||||
CHECK(std::string("{\"data\":[[1,2,3],[4,5,6]]}") == json);
|
||||
CHECK("{\"data\":[[1,2,3],[4,5,6]]}"_s == json);
|
||||
}
|
||||
|
||||
SECTION("int[][] -> JsonDocument") {
|
||||
@ -151,7 +152,7 @@ TEST_CASE("copyArray()") {
|
||||
CHECK(ok);
|
||||
|
||||
serializeJson(doc, json);
|
||||
CHECK(std::string("[[1,2,3],[4,5,6]]") == json);
|
||||
CHECK("[[1,2,3],[4,5,6]]"_s == json);
|
||||
}
|
||||
|
||||
SECTION("int[][] -> JsonArray, but not enough memory") {
|
||||
@ -223,9 +224,9 @@ TEST_CASE("copyArray()") {
|
||||
size_t result = copyArray(array, destination);
|
||||
|
||||
CHECK(3 == result);
|
||||
CHECK(std::string("a12345") == destination[0]);
|
||||
CHECK(std::string("b123456") == destination[1]);
|
||||
CHECK(std::string("c123456") == destination[2]); // truncated
|
||||
CHECK("a12345"_s == destination[0]);
|
||||
CHECK("b123456"_s == destination[1]);
|
||||
CHECK("c123456"_s == destination[2]); // truncated
|
||||
CHECK(std::string("") == destination[3]);
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,12 @@ TEST_CASE("JsonArray::remove()") {
|
||||
REQUIRE(array[1] == 2);
|
||||
}
|
||||
|
||||
SECTION("remove end()") {
|
||||
array.remove(array.end());
|
||||
|
||||
REQUIRE(3 == array.size());
|
||||
}
|
||||
|
||||
SECTION("In a loop") {
|
||||
for (JsonArray::iterator it = array.begin(); it != array.end(); ++it) {
|
||||
if (*it == 2)
|
||||
@ -88,6 +94,15 @@ TEST_CASE("JsonArray::remove()") {
|
||||
JsonArray unboundArray;
|
||||
unboundArray.remove(unboundArray.begin());
|
||||
}
|
||||
|
||||
SECTION("use JsonVariant as index") {
|
||||
array.remove(array[3]); // no effect with null variant
|
||||
array.remove(array[0]); // remove element at index 1
|
||||
|
||||
REQUIRE(2 == array.size());
|
||||
REQUIRE(array[0] == 1);
|
||||
REQUIRE(array[1] == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Removed elements are recycled") {
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
static void eraseString(std::string& str) {
|
||||
char* p = const_cast<char*>(str.c_str());
|
||||
while (*p)
|
||||
@ -19,7 +21,7 @@ TEST_CASE("std::string") {
|
||||
std::string value("hello");
|
||||
array.add(value);
|
||||
eraseString(value);
|
||||
REQUIRE(std::string("hello") == array[0]);
|
||||
REQUIRE("hello"_s == array[0]);
|
||||
}
|
||||
|
||||
SECTION("operator[]") {
|
||||
@ -27,6 +29,6 @@ TEST_CASE("std::string") {
|
||||
array.add("hello");
|
||||
array[0] = value;
|
||||
eraseString(value);
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonArray::operator[]") {
|
||||
SpyingAllocator spy;
|
||||
@ -129,7 +130,7 @@ TEST_CASE("JsonArray::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string") {
|
||||
array[0] = std::string("world");
|
||||
array[0] = "world"_s;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
@ -150,7 +151,7 @@ TEST_CASE("JsonArray::operator[]") {
|
||||
array.add("hello");
|
||||
array[0].set(vla);
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
|
||||
SECTION("operator=(VLA)") {
|
||||
@ -161,7 +162,16 @@ TEST_CASE("JsonArray::operator[]") {
|
||||
array.add("hello");
|
||||
array[0] = vla;
|
||||
|
||||
REQUIRE(std::string("world") == array[0]);
|
||||
REQUIRE("world"_s == array[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("Use a JsonVariant as index") {
|
||||
array[0] = 1;
|
||||
array[1] = 2;
|
||||
array[2] = 3;
|
||||
|
||||
REQUIRE(array[array[1]] == 3);
|
||||
REQUIRE(array[array[3]] == nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,15 @@ TEST_CASE("JsonArrayConst::operator[]") {
|
||||
doc.add(2);
|
||||
doc.add(3);
|
||||
|
||||
REQUIRE(1 == arr[0].as<int>());
|
||||
REQUIRE(2 == arr[1].as<int>());
|
||||
REQUIRE(3 == arr[2].as<int>());
|
||||
REQUIRE(0 == arr[3].as<int>());
|
||||
SECTION("int") {
|
||||
REQUIRE(1 == arr[0].as<int>());
|
||||
REQUIRE(2 == arr[1].as<int>());
|
||||
REQUIRE(3 == arr[2].as<int>());
|
||||
REQUIRE(0 == arr[3].as<int>());
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
REQUIRE(2 == arr[arr[0]].as<int>());
|
||||
REQUIRE(0 == arr[arr[3]].as<int>());
|
||||
}
|
||||
}
|
||||
|
@ -69,14 +69,32 @@ TEST_CASE("deserialize JSON array") {
|
||||
REQUIRE(arr[1] == 84);
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
SECTION("Float") {
|
||||
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);
|
||||
REQUIRE(arr[0].as<float>() == Approx(4.2f));
|
||||
REQUIRE(arr[1] == 1e2f);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Reallocate(sizeofPool(), sizeofPool(2)),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
DeserializationError err = deserializeJson(doc, "[4.2123456,-7E89]");
|
||||
JsonArray arr = doc.as<JsonArray>();
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(2 == arr.size());
|
||||
REQUIRE(arr[0].as<double>() == Approx(4.2123456));
|
||||
REQUIRE(arr[1] == -7E89);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Reallocate(sizeofPool(), sizeofPool(4)),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("Unsigned long") {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
@ -15,7 +16,7 @@ using ArduinoJson::detail::sizeofObject;
|
||||
TEST_CASE("deserializeJson(JsonDocument&)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
doc.add("hello"_s);
|
||||
spy.clearLog();
|
||||
|
||||
auto err = deserializeJson(doc, "[42]");
|
||||
@ -34,7 +35,7 @@ TEST_CASE("deserializeJson(JsonVariant)") {
|
||||
SECTION("variant is bound") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
doc.add("hello"_s);
|
||||
spy.clearLog();
|
||||
|
||||
JsonVariant variant = doc[0];
|
||||
@ -60,7 +61,7 @@ TEST_CASE("deserializeJson(JsonVariant)") {
|
||||
TEST_CASE("deserializeJson(ElementProxy)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc.add(std::string("hello"));
|
||||
doc.add("hello"_s);
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("element already exists") {
|
||||
@ -85,7 +86,7 @@ TEST_CASE("deserializeJson(ElementProxy)") {
|
||||
TEST_CASE("deserializeJson(MemberProxy)") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc[std::string("hello")] = std::string("world");
|
||||
doc["hello"_s] = "world"_s;
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("member already exists") {
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
TEST_CASE("deserializeJson() returns IncompleteInput") {
|
||||
const char* testCases[] = {
|
||||
// strings
|
||||
@ -118,3 +120,43 @@ TEST_CASE("deserializeJson() returns NoMemory if string length overflows") {
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("deserializeJson() returns NoMemory if extension allocation fails") {
|
||||
JsonDocument doc(FailingAllocator::instance());
|
||||
|
||||
SECTION("uint32_t should pass") {
|
||||
auto err = deserializeJson(doc, "4294967295");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("uint64_t should fail") {
|
||||
auto err = deserializeJson(doc, "18446744073709551615");
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
SECTION("int32_t should pass") {
|
||||
auto err = deserializeJson(doc, "-2147483648");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("int64_t should fail") {
|
||||
auto err = deserializeJson(doc, "-9223372036854775808");
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
SECTION("float should pass") {
|
||||
auto err = deserializeJson(doc, "3.402823e38");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("double should fail") {
|
||||
auto err = deserializeJson(doc, "1.7976931348623157e308");
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
@ -732,7 +733,7 @@ TEST_CASE("Overloads") {
|
||||
}
|
||||
|
||||
SECTION("const std::string&, Filter") {
|
||||
deserializeJson(doc, std::string("{}"), Filter(filter));
|
||||
deserializeJson(doc, "{}"_s, Filter(filter));
|
||||
}
|
||||
|
||||
SECTION("std::istream&, Filter") {
|
||||
@ -760,7 +761,7 @@ TEST_CASE("Overloads") {
|
||||
}
|
||||
|
||||
SECTION("const std::string&, Filter, NestingLimit") {
|
||||
deserializeJson(doc, std::string("{}"), Filter(filter), NestingLimit(5));
|
||||
deserializeJson(doc, "{}"_s, Filter(filter), NestingLimit(5));
|
||||
}
|
||||
|
||||
SECTION("std::istream&, Filter, NestingLimit") {
|
||||
@ -788,7 +789,7 @@ TEST_CASE("Overloads") {
|
||||
}
|
||||
|
||||
SECTION("const std::string&, NestingLimit, Filter") {
|
||||
deserializeJson(doc, std::string("{}"), NestingLimit(5), Filter(filter));
|
||||
deserializeJson(doc, "{}"_s, NestingLimit(5), Filter(filter));
|
||||
}
|
||||
|
||||
SECTION("std::istream&, NestingLimit, Filter") {
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "CustomReader.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
|
||||
@ -69,7 +70,7 @@ TEST_CASE("deserializeJson(const std::string&)") {
|
||||
}
|
||||
|
||||
SECTION("should accept temporary string") {
|
||||
DeserializationError err = deserializeJson(doc, std::string("[42]"));
|
||||
DeserializationError err = deserializeJson(doc, "[42]"_s);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
@ -82,7 +83,7 @@ TEST_CASE("deserializeJson(const std::string&)") {
|
||||
|
||||
JsonArray array = doc.as<JsonArray>();
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(std::string("hello") == array[0]);
|
||||
REQUIRE("hello"_s == array[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +109,7 @@ TEST_CASE("deserializeJson(std::istream&)") {
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(1 == obj.size());
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("Should not read after the closing brace of an empty object") {
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
#define SHOULD_WORK(expression) REQUIRE(DeserializationError::Ok == expression);
|
||||
#define SHOULD_FAIL(expression) \
|
||||
REQUIRE(DeserializationError::TooDeep == expression);
|
||||
@ -63,23 +65,23 @@ TEST_CASE("JsonDeserializer 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));
|
||||
SHOULD_WORK(deserializeJson(doc, "\"toto\""_s, nesting));
|
||||
SHOULD_WORK(deserializeJson(doc, "123"_s, nesting));
|
||||
SHOULD_WORK(deserializeJson(doc, "true"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "[]"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "{}"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "[\"toto\"]"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":1}"_s, 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));
|
||||
SHOULD_WORK(deserializeJson(doc, "[\"toto\"]"_s, nesting));
|
||||
SHOULD_WORK(deserializeJson(doc, "{\"toto\":1}"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":{}}"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "{\"toto\":[]}"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "[[\"toto\"]]"_s, nesting));
|
||||
SHOULD_FAIL(deserializeJson(doc, "[{\"toto\":1}]"_s, nesting));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,15 +155,27 @@ TEST_CASE("deserialize JSON object") {
|
||||
REQUIRE(obj["key2"] == -42);
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
SECTION("Float") {
|
||||
DeserializationError err =
|
||||
deserializeJson(doc, "{\"key1\":12.345,\"key2\":-7E89}");
|
||||
deserializeJson(doc, "{\"key1\":12.345,\"key2\":-7E3}");
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.is<JsonObject>());
|
||||
REQUIRE(obj.size() == 2);
|
||||
REQUIRE(obj["key1"] == 12.345);
|
||||
REQUIRE(obj["key1"].as<float>() == Approx(12.345f));
|
||||
REQUIRE(obj["key2"] == -7E3f);
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
DeserializationError err =
|
||||
deserializeJson(doc, "{\"key1\":12.3456789,\"key2\":-7E89}");
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.is<JsonObject>());
|
||||
REQUIRE(obj.size() == 2);
|
||||
REQUIRE(obj["key1"].as<double>() == Approx(12.3456789));
|
||||
REQUIRE(obj["key2"] == -7E89);
|
||||
}
|
||||
|
||||
@ -308,12 +320,12 @@ TEST_CASE("deserialize JSON object") {
|
||||
REQUIRE(doc["a"] == 2);
|
||||
}
|
||||
|
||||
SECTION("NUL in keys") { // we don't support NULs in keys
|
||||
SECTION("NUL in keys") {
|
||||
DeserializationError err =
|
||||
deserializeJson(doc, "{\"x\\u0000a\":1,\"x\\u0000b\":2}");
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
REQUIRE(doc.as<std::string>() == "{\"x\":2}");
|
||||
REQUIRE(doc.as<std::string>() == "{\"x\\u0000a\":1,\"x\\u0000b\":2}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,22 @@ TEST_CASE("Truncated JSON string") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Escape single quote in single quoted string") {
|
||||
JsonDocument doc;
|
||||
|
||||
DeserializationError err = deserializeJson(doc, "'ab\\\'cd'");
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
CHECK(doc.as<std::string>() == "ab\'cd");
|
||||
}
|
||||
|
||||
TEST_CASE("Escape double quote in double quoted string") {
|
||||
JsonDocument doc;
|
||||
|
||||
DeserializationError err = deserializeJson(doc, "'ab\\\"cd'");
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
CHECK(doc.as<std::string>() == "ab\"cd");
|
||||
}
|
||||
|
||||
TEST_CASE("Invalid JSON string") {
|
||||
const char* testCases[] = {"'\\u'", "'\\u000g'", "'\\u000'",
|
||||
"'\\u000G'", "'\\u000/'", "'\\x1234'"};
|
||||
|
@ -9,7 +9,6 @@ add_executable(JsonDocumentTests
|
||||
clear.cpp
|
||||
compare.cpp
|
||||
constructor.cpp
|
||||
containsKey.cpp
|
||||
ElementProxy.cpp
|
||||
isNull.cpp
|
||||
issue1120.cpp
|
||||
@ -17,6 +16,7 @@ add_executable(JsonDocumentTests
|
||||
nesting.cpp
|
||||
overflowed.cpp
|
||||
remove.cpp
|
||||
set.cpp
|
||||
shrinkToFit.cpp
|
||||
size.cpp
|
||||
subscript.cpp
|
||||
|
@ -5,7 +5,9 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
typedef ArduinoJson::detail::ElementProxy<JsonDocument&> ElementProxy;
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ElementProxy = ArduinoJson::detail::ElementProxy<JsonDocument&>;
|
||||
|
||||
TEST_CASE("ElementProxy::add()") {
|
||||
JsonDocument doc;
|
||||
@ -24,13 +26,25 @@ TEST_CASE("ElementProxy::add()") {
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
}
|
||||
|
||||
SECTION("set(char[])") {
|
||||
SECTION("add(char[])") {
|
||||
char s[] = "world";
|
||||
ep.add(s);
|
||||
strcpy(s, "!!!!!");
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(vla)") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
ep.add(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[[\"world\"]]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("ElementProxy::clear()") {
|
||||
@ -121,7 +135,7 @@ TEST_CASE("ElementProxy::remove()") {
|
||||
ep["a"] = 1;
|
||||
ep["b"] = 2;
|
||||
|
||||
ep.remove(std::string("b"));
|
||||
ep.remove("b"_s);
|
||||
|
||||
REQUIRE(ep.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
@ -164,6 +178,18 @@ TEST_CASE("ElementProxy::set()") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\"world\"]");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(VLA)") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
ep.set(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[\"world\"]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("ElementProxy::size()") {
|
||||
@ -203,6 +229,18 @@ TEST_CASE("ElementProxy::operator[]") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[null,[null,null,42]]");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set VLA") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
ep[0] = vla;
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[null,[\"world\"]]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("ElementProxy cast to JsonVariantConst") {
|
||||
|
@ -9,12 +9,13 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
|
||||
typedef ArduinoJson::detail::MemberProxy<JsonDocument&, const char*>
|
||||
MemberProxy;
|
||||
using MemberProxy =
|
||||
ArduinoJson::detail::MemberProxy<JsonDocument&, const char*>;
|
||||
|
||||
TEST_CASE("MemberProxy::add()") {
|
||||
JsonDocument doc;
|
||||
@ -31,6 +32,18 @@ TEST_CASE("MemberProxy::add()") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("add(vla)") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
mp.add(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":[\"world\"]}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::clear()") {
|
||||
@ -92,33 +105,14 @@ TEST_CASE("MemberProxy::operator==()") {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::containsKey()") {
|
||||
JsonDocument doc;
|
||||
MemberProxy mp = doc["hello"];
|
||||
|
||||
SECTION("containsKey(const char*)") {
|
||||
mp["key"] = "value";
|
||||
|
||||
REQUIRE(mp.containsKey("key") == true);
|
||||
REQUIRE(mp.containsKey("key") == true);
|
||||
}
|
||||
|
||||
SECTION("containsKey(std::string)") {
|
||||
mp["key"] = "value";
|
||||
|
||||
REQUIRE(mp.containsKey(std::string("key")) == true);
|
||||
REQUIRE(mp.containsKey(std::string("key")) == true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::operator|()") {
|
||||
JsonDocument doc;
|
||||
|
||||
SECTION("const char*") {
|
||||
doc["a"] = "hello";
|
||||
|
||||
REQUIRE((doc["a"] | "world") == std::string("hello"));
|
||||
REQUIRE((doc["b"] | "world") == std::string("world"));
|
||||
REQUIRE((doc["a"] | "world") == "hello"_s);
|
||||
REQUIRE((doc["b"] | "world") == "world"_s);
|
||||
}
|
||||
|
||||
SECTION("Issue #1411") {
|
||||
@ -128,7 +122,7 @@ TEST_CASE("MemberProxy::operator|()") {
|
||||
// to trigger the bug
|
||||
const char* sensor = doc["sensor"] | test; // "gps"
|
||||
|
||||
REQUIRE(sensor == std::string("gps"));
|
||||
REQUIRE(sensor == "gps"_s);
|
||||
}
|
||||
|
||||
SECTION("Issue #1415") {
|
||||
@ -170,7 +164,7 @@ TEST_CASE("MemberProxy::remove()") {
|
||||
mp["a"] = 1;
|
||||
mp["b"] = 2;
|
||||
|
||||
mp.remove(std::string("b"));
|
||||
mp.remove("b"_s);
|
||||
|
||||
REQUIRE(mp.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
@ -213,6 +207,18 @@ TEST_CASE("MemberProxy::set()") {
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("set(vla)") {
|
||||
size_t i = 8;
|
||||
char vla[i];
|
||||
strcpy(vla, "world");
|
||||
|
||||
mp.set(vla);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy::size()") {
|
||||
@ -286,8 +292,8 @@ TEST_CASE("Deduplicate keys") {
|
||||
JsonDocument doc(&spy);
|
||||
|
||||
SECTION("std::string") {
|
||||
doc[0][std::string("example")] = 1;
|
||||
doc[1][std::string("example")] = 2;
|
||||
doc[0]["example"_s] = 1;
|
||||
doc[1]["example"_s] = 2;
|
||||
|
||||
const char* key1 = doc[0].as<JsonObject>().begin()->key().c_str();
|
||||
const char* key2 = doc[1].as<JsonObject>().begin()->key().c_str();
|
||||
@ -344,19 +350,51 @@ TEST_CASE("Deduplicate keys") {
|
||||
}
|
||||
|
||||
TEST_CASE("MemberProxy under memory constraints") {
|
||||
KillswitchAllocator killswitch;
|
||||
SpyingAllocator spy(&killswitch);
|
||||
TimebombAllocator timebomb(1);
|
||||
SpyingAllocator spy(&timebomb);
|
||||
JsonDocument doc(&spy);
|
||||
|
||||
SECTION("key allocation fails") {
|
||||
killswitch.on();
|
||||
SECTION("key slot allocation fails") {
|
||||
timebomb.setCountdown(0);
|
||||
|
||||
doc[std::string("hello")] = "world";
|
||||
doc["hello"_s] = "world";
|
||||
|
||||
REQUIRE(doc.is<JsonObject>());
|
||||
REQUIRE(doc.size() == 0);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
AllocateFail(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("value slot allocation fails") {
|
||||
timebomb.setCountdown(1);
|
||||
|
||||
// fill the pool entirely, but leave one slot for the key
|
||||
doc["foo"][ARDUINOJSON_POOL_CAPACITY - 4] = 1;
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
|
||||
doc["hello"_s] = "world";
|
||||
|
||||
REQUIRE(doc.is<JsonObject>());
|
||||
REQUIRE(doc.size() == 1);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
AllocateFail(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("key string allocation fails") {
|
||||
timebomb.setCountdown(1);
|
||||
|
||||
doc["hello"_s] = "world";
|
||||
|
||||
REQUIRE(doc.is<JsonObject>());
|
||||
REQUIRE(doc.size() == 0);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
AllocateFail(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
|
||||
@ -35,8 +36,8 @@ TEST_CASE("JsonDocument::add(T)") {
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
doc.add(std::string("example"));
|
||||
doc.add(std::string("example"));
|
||||
doc.add("example"_s);
|
||||
doc.add("example"_s);
|
||||
|
||||
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
@ -78,6 +79,24 @@ TEST_CASE("JsonDocument::add(T)") {
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "example");
|
||||
|
||||
doc.add(vla);
|
||||
doc.add(vla);
|
||||
|
||||
CHECK(doc[0].as<const char*>() == doc[1].as<const char*>());
|
||||
REQUIRE("example"_s == doc[0]);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonDocument::add<T>()") {
|
||||
@ -90,15 +109,57 @@ TEST_CASE("JsonDocument::add<T>()") {
|
||||
REQUIRE(doc.as<std::string>() == "[[1,2]]");
|
||||
}
|
||||
|
||||
SECTION("JsonObject") {
|
||||
JsonObject object = doc.add<JsonObject>();
|
||||
object["hello"] = "world";
|
||||
REQUIRE(doc.as<std::string>() == "[{\"hello\":\"world\"}]");
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
JsonVariant variant = doc.add<JsonVariant>();
|
||||
variant.set(42);
|
||||
REQUIRE(doc.as<std::string>() == "[42]");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonObject::add(JsonObject) ") {
|
||||
JsonDocument doc1;
|
||||
doc1["hello"_s] = "world"_s;
|
||||
|
||||
TimebombAllocator allocator(10);
|
||||
SpyingAllocator spy(&allocator);
|
||||
JsonDocument doc2(&spy);
|
||||
|
||||
SECTION("success") {
|
||||
bool result = doc2.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("partial failure") { // issue #2081
|
||||
allocator.setCountdown(2);
|
||||
|
||||
bool result = doc2.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc2.as<std::string>() == "[]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
AllocateFail(sizeofString("world")),
|
||||
Deallocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("complete failure") {
|
||||
allocator.setCountdown(0);
|
||||
|
||||
bool result = doc2.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc2.as<std::string>() == "[]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
AllocateFail(sizeofPool()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument assignment") {
|
||||
SpyingAllocator spyingAllocator;
|
||||
@ -21,8 +22,8 @@ TEST_CASE("JsonDocument assignment") {
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@ -53,8 +54,8 @@ TEST_CASE("JsonDocument assignment") {
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "{\"hello\":\"world\"}");
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@ -62,7 +63,7 @@ TEST_CASE("JsonDocument assignment") {
|
||||
SECTION("Move assign") {
|
||||
{
|
||||
JsonDocument doc1(&spyingAllocator);
|
||||
doc1[std::string("hello")] = std::string("world");
|
||||
doc1["hello"_s] = "world"_s;
|
||||
JsonDocument doc2(&spyingAllocator);
|
||||
|
||||
doc2 = std::move(doc1);
|
||||
@ -71,8 +72,8 @@ TEST_CASE("JsonDocument assignment") {
|
||||
REQUIRE(doc1.as<std::string>() == "null");
|
||||
}
|
||||
REQUIRE(spyingAllocator.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
Deallocate(sizeofString("hello")),
|
||||
Deallocate(sizeofString("world")),
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::clear()") {
|
||||
SpyingAllocator spy;
|
||||
@ -22,7 +23,7 @@ TEST_CASE("JsonDocument::clear()") {
|
||||
}
|
||||
|
||||
SECTION("releases resources") {
|
||||
doc[std::string("hello")] = std::string("world");
|
||||
doc["hello"_s] = "world"_s;
|
||||
spy.clearLog();
|
||||
|
||||
doc.clear();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::addPadding;
|
||||
|
||||
@ -20,7 +21,7 @@ TEST_CASE("JsonDocument constructor") {
|
||||
SECTION("JsonDocument(const JsonDocument&)") {
|
||||
{
|
||||
JsonDocument doc1(&spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
doc1.set("The size of this string is 32!!"_s);
|
||||
|
||||
JsonDocument doc2(doc1);
|
||||
|
||||
@ -38,7 +39,7 @@ TEST_CASE("JsonDocument constructor") {
|
||||
SECTION("JsonDocument(JsonDocument&&)") {
|
||||
{
|
||||
JsonDocument doc1(&spyingAllocator);
|
||||
doc1.set(std::string("The size of this string is 32!!"));
|
||||
doc1.set("The size of this string is 32!!"_s);
|
||||
|
||||
JsonDocument doc2(std::move(doc1));
|
||||
|
||||
@ -117,4 +118,31 @@ TEST_CASE("JsonDocument constructor") {
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "hello");
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(JsonVariantConst)") {
|
||||
JsonDocument doc1;
|
||||
deserializeJson(doc1, "\"hello\"");
|
||||
|
||||
JsonDocument doc2(doc1.as<JsonVariantConst>());
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "hello");
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(ElementProxy)") {
|
||||
JsonDocument doc1;
|
||||
deserializeJson(doc1, "[\"hello\",\"world\"]");
|
||||
|
||||
JsonDocument doc2(doc1[1]);
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "world");
|
||||
}
|
||||
|
||||
SECTION("JsonDocument(MemberProxy)") {
|
||||
JsonDocument doc1;
|
||||
deserializeJson(doc1, "{\"hello\":\"world\"}");
|
||||
|
||||
JsonDocument doc2(doc1["hello"]);
|
||||
|
||||
REQUIRE(doc2.as<std::string>() == "world");
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonDocument::containsKey()") {
|
||||
JsonDocument doc;
|
||||
|
||||
SECTION("returns true on object") {
|
||||
doc["hello"] = "world";
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == true);
|
||||
}
|
||||
|
||||
SECTION("returns true when value is null") {
|
||||
doc["hello"] = static_cast<const char*>(0);
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == true);
|
||||
}
|
||||
|
||||
SECTION("returns true when key is a std::string") {
|
||||
doc["hello"] = "world";
|
||||
|
||||
REQUIRE(doc.containsKey(std::string("hello")) == true);
|
||||
}
|
||||
|
||||
SECTION("returns false on object") {
|
||||
doc["world"] = "hello";
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
|
||||
SECTION("returns false on array") {
|
||||
doc.add("hello");
|
||||
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
|
||||
SECTION("returns false on null") {
|
||||
REQUIRE(doc.containsKey("hello") == false);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("Issue #1120") {
|
||||
JsonDocument doc;
|
||||
constexpr char str[] =
|
||||
@ -10,12 +12,12 @@ TEST_CASE("Issue #1120") {
|
||||
|
||||
SECTION("MemberProxy<std::string>::isNull()") {
|
||||
SECTION("returns false") {
|
||||
auto value = doc[std::string("contents")];
|
||||
auto value = doc["contents"_s];
|
||||
CHECK(value.isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("returns true") {
|
||||
auto value = doc[std::string("zontents")];
|
||||
auto value = doc["zontents"_s];
|
||||
CHECK(value.isNull() == true);
|
||||
}
|
||||
}
|
||||
@ -46,12 +48,12 @@ TEST_CASE("Issue #1120") {
|
||||
|
||||
SECTION("MemberProxy<ElementProxy<MemberProxy>, std::string>::isNull()") {
|
||||
SECTION("returns false") {
|
||||
auto value = doc["contents"][1][std::string("module")];
|
||||
auto value = doc["contents"][1]["module"_s];
|
||||
CHECK(value.isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("returns true") {
|
||||
auto value = doc["contents"][1][std::string("zodule")];
|
||||
auto value = doc["contents"][1]["zodule"_s];
|
||||
CHECK(value.isNull() == true);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::overflowed()") {
|
||||
TimebombAllocator timebomb(10);
|
||||
@ -30,13 +31,13 @@ TEST_CASE("JsonDocument::overflowed()") {
|
||||
|
||||
SECTION("returns true after a failed string copy") {
|
||||
timebomb.setCountdown(0);
|
||||
doc.add(std::string("example"));
|
||||
doc.add("example"_s);
|
||||
CHECK(doc.overflowed() == true);
|
||||
}
|
||||
|
||||
SECTION("returns false after a successful string copy") {
|
||||
timebomb.setCountdown(3);
|
||||
doc.add(std::string("example"));
|
||||
doc.add("example"_s);
|
||||
CHECK(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::remove()") {
|
||||
JsonDocument doc;
|
||||
|
||||
@ -31,7 +33,7 @@ TEST_CASE("JsonDocument::remove()") {
|
||||
doc["a"] = 1;
|
||||
doc["b"] = 2;
|
||||
|
||||
doc.remove(std::string("b"));
|
||||
doc.remove("b"_s);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
@ -49,4 +51,25 @@ TEST_CASE("JsonDocument::remove()") {
|
||||
REQUIRE(doc.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("remove(JsonVariant) from object") {
|
||||
doc["a"] = 1;
|
||||
doc["b"] = 2;
|
||||
doc["c"] = "b";
|
||||
|
||||
doc.remove(doc["c"]);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"a\":1,\"c\":\"b\"}");
|
||||
}
|
||||
|
||||
SECTION("remove(JsonVariant) from array") {
|
||||
doc[0] = 3;
|
||||
doc[1] = 2;
|
||||
doc[2] = 1;
|
||||
|
||||
doc.remove(doc[2]);
|
||||
doc.remove(doc[3]); // noop
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "[3,1]");
|
||||
}
|
||||
}
|
||||
|
79
extras/tests/JsonDocument/set.cpp
Normal file
79
extras/tests/JsonDocument/set.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
#define ARDUINOJSON_ENABLE_ARDUINO_STRING 1
|
||||
#define ARDUINOJSON_ENABLE_PROGMEM 1
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::set()") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
|
||||
SECTION("integer") {
|
||||
doc.set(42);
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "42");
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
doc.set("example");
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
doc.set("example"_s);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("char*") {
|
||||
char value[] = "example";
|
||||
doc.set(value);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("Arduino String") {
|
||||
doc.set(String("example"));
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("Flash string") {
|
||||
doc.set(F("example"));
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "example");
|
||||
|
||||
doc.set(vla);
|
||||
|
||||
REQUIRE(doc.as<const char*>() == "example"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("example")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
@ -78,7 +79,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
}
|
||||
|
||||
SECTION("owned string") {
|
||||
doc.set(std::string("abcdefg"));
|
||||
doc.set("abcdefg"_s);
|
||||
REQUIRE(doc.as<std::string>() == "abcdefg");
|
||||
|
||||
doc.shrinkToFit();
|
||||
@ -114,15 +115,15 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
}
|
||||
|
||||
SECTION("owned key") {
|
||||
doc[std::string("abcdefg")] = 42;
|
||||
doc["abcdefg"_s] = 42;
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(doc.as<std::string>() == "{\"abcdefg\":42}");
|
||||
REQUIRE(spyingAllocator.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofString("abcdefg")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("abcdefg")),
|
||||
Reallocate(sizeofPool(), sizeofObject(1)),
|
||||
});
|
||||
}
|
||||
@ -141,7 +142,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
}
|
||||
|
||||
SECTION("owned string in array") {
|
||||
doc.add(std::string("abcdefg"));
|
||||
doc.add("abcdefg"_s);
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
@ -168,7 +169,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
}
|
||||
|
||||
SECTION("owned string in object") {
|
||||
doc["key"] = std::string("abcdefg");
|
||||
doc["key"] = "abcdefg"_s;
|
||||
|
||||
doc.shrinkToFit();
|
||||
|
||||
@ -177,7 +178,7 @@ TEST_CASE("JsonDocument::shrinkToFit()") {
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("abcdefg")),
|
||||
Reallocate(sizeofPool(), sizeofPool(1)),
|
||||
Reallocate(sizeofPool(), sizeofPool(2)),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,34 +5,77 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonDocument::operator[]") {
|
||||
JsonDocument doc;
|
||||
const JsonDocument& cdoc = doc;
|
||||
|
||||
SECTION("object") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
doc["abc"_s] = "ABC";
|
||||
doc["abc\0d"_s] = "ABCD";
|
||||
|
||||
SECTION("const char*") {
|
||||
REQUIRE(doc["hello"] == "world");
|
||||
REQUIRE(cdoc["hello"] == "world");
|
||||
REQUIRE(doc["abc"] == "ABC");
|
||||
REQUIRE(cdoc["abc"] == "ABC");
|
||||
}
|
||||
|
||||
SECTION("std::string") {
|
||||
REQUIRE(doc[std::string("hello")] == "world");
|
||||
REQUIRE(cdoc[std::string("hello")] == "world");
|
||||
REQUIRE(doc["abc"_s] == "ABC");
|
||||
REQUIRE(cdoc["abc"_s] == "ABC");
|
||||
REQUIRE(doc["abc\0d"_s] == "ABCD");
|
||||
REQUIRE(cdoc["abc\0d"_s] == "ABCD");
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
doc["key1"] = "abc";
|
||||
doc["key2"] = "abc\0d"_s;
|
||||
doc["key3"] = "foo";
|
||||
|
||||
CHECK(doc[doc["key1"]] == "ABC");
|
||||
CHECK(doc[doc["key2"]] == "ABCD");
|
||||
CHECK(doc[doc["key3"]] == nullptr);
|
||||
CHECK(doc[doc["key4"]] == nullptr);
|
||||
|
||||
CHECK(cdoc[cdoc["key1"]] == "ABC");
|
||||
CHECK(cdoc[cdoc["key2"]] == "ABCD");
|
||||
CHECK(cdoc[cdoc["key3"]] == nullptr);
|
||||
CHECK(cdoc[cdoc["key4"]] == nullptr);
|
||||
}
|
||||
|
||||
SECTION("supports operator|") {
|
||||
REQUIRE((doc["hello"] | "nope") == std::string("world"));
|
||||
REQUIRE((doc["world"] | "nope") == std::string("nope"));
|
||||
REQUIRE((doc["abc"] | "nope") == "ABC"_s);
|
||||
REQUIRE((doc["def"] | "nope") == "nope"_s);
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
!defined(SUBSCRIPT_CONFLICTS_WITH_BUILTIN_OPERATOR)
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
doc[vla] = "world";
|
||||
|
||||
REQUIRE(doc[vla] == "world");
|
||||
REQUIRE(cdoc[vla] == "world");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("array") {
|
||||
deserializeJson(doc, "[\"hello\",\"world\"]");
|
||||
|
||||
REQUIRE(doc[1] == "world");
|
||||
REQUIRE(cdoc[1] == "world");
|
||||
SECTION("int") {
|
||||
REQUIRE(doc[1] == "world");
|
||||
REQUIRE(cdoc[1] == "world");
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
doc[2] = 1;
|
||||
REQUIRE(doc[doc[2]] == "world");
|
||||
REQUIRE(cdoc[doc[2]] == "world");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,12 @@
|
||||
add_executable(JsonObjectTests
|
||||
clear.cpp
|
||||
compare.cpp
|
||||
containsKey.cpp
|
||||
copy.cpp
|
||||
equals.cpp
|
||||
isNull.cpp
|
||||
iterator.cpp
|
||||
nesting.cpp
|
||||
remove.cpp
|
||||
set.cpp
|
||||
size.cpp
|
||||
std_string.cpp
|
||||
subscript.cpp
|
||||
|
@ -1,33 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonObject::containsKey()") {
|
||||
JsonDocument doc;
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = 42;
|
||||
|
||||
SECTION("returns true only if key is present") {
|
||||
REQUIRE(false == obj.containsKey("world"));
|
||||
REQUIRE(true == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
SECTION("returns false after remove()") {
|
||||
obj.remove("hello");
|
||||
|
||||
REQUIRE(false == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("key is a VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == obj.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
}
|
@ -80,4 +80,10 @@ TEST_CASE("JsonObject::remove()") {
|
||||
JsonObject unboundObject;
|
||||
unboundObject.remove(unboundObject.begin());
|
||||
}
|
||||
|
||||
SECTION("remove(JsonVariant)") {
|
||||
obj["key"] = "b";
|
||||
obj.remove(obj["key"]);
|
||||
REQUIRE("{\"a\":0,\"c\":2,\"key\":\"b\"}" == doc.as<std::string>());
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonObject::set()") {
|
||||
SpyingAllocator spy;
|
||||
@ -22,20 +23,20 @@ TEST_CASE("JsonObject::set()") {
|
||||
bool success = obj2.set(obj1);
|
||||
|
||||
REQUIRE(success == true);
|
||||
REQUIRE(obj2["hello"] == std::string("world"));
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("copy local string value") {
|
||||
obj1["hello"] = std::string("world");
|
||||
obj1["hello"] = "world"_s;
|
||||
spy.clearLog();
|
||||
|
||||
bool success = obj2.set(obj1);
|
||||
|
||||
REQUIRE(success == true);
|
||||
REQUIRE(obj2["hello"] == std::string("world"));
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
@ -43,16 +44,16 @@ TEST_CASE("JsonObject::set()") {
|
||||
}
|
||||
|
||||
SECTION("copy local key") {
|
||||
obj1[std::string("hello")] = "world";
|
||||
obj1["hello"_s] = "world";
|
||||
spy.clearLog();
|
||||
|
||||
bool success = obj2.set(obj1);
|
||||
|
||||
REQUIRE(success == true);
|
||||
REQUIRE(obj2["hello"] == std::string("world"));
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
@ -63,10 +64,10 @@ TEST_CASE("JsonObject::set()") {
|
||||
bool success = obj2.set(obj1);
|
||||
|
||||
REQUIRE(success == true);
|
||||
REQUIRE(obj2["hello"] == std::string("world"));
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@ -78,10 +79,10 @@ TEST_CASE("JsonObject::set()") {
|
||||
bool success = obj2.set(obj1);
|
||||
|
||||
REQUIRE(success == true);
|
||||
REQUIRE(obj2["hello"] == std::string("world"));
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@ -91,7 +92,7 @@ TEST_CASE("JsonObject::set()") {
|
||||
|
||||
obj2.set(static_cast<JsonObjectConst>(obj1));
|
||||
|
||||
REQUIRE(obj2["hello"] == std::string("world"));
|
||||
REQUIRE(obj2["hello"] == "world"_s);
|
||||
}
|
||||
|
||||
SECTION("copy fails in the middle of an object") {
|
||||
@ -99,8 +100,8 @@ TEST_CASE("JsonObject::set()") {
|
||||
JsonDocument doc3(&timebomb);
|
||||
JsonObject obj3 = doc3.to<JsonObject>();
|
||||
|
||||
obj1[std::string("a")] = 1;
|
||||
obj1[std::string("b")] = 2;
|
||||
obj1["a"_s] = 1;
|
||||
obj1["b"_s] = 2;
|
||||
|
||||
bool success = obj3.set(obj1);
|
||||
|
||||
@ -113,12 +114,12 @@ TEST_CASE("JsonObject::set()") {
|
||||
JsonDocument doc3(&timebomb);
|
||||
JsonObject obj3 = doc3.to<JsonObject>();
|
||||
|
||||
obj1["hello"][0] = std::string("world");
|
||||
obj1["hello"][0] = "world"_s;
|
||||
|
||||
bool success = obj3.set(obj1);
|
||||
|
||||
REQUIRE(success == false);
|
||||
REQUIRE(doc3.as<std::string>() == "{\"hello\":[null]}");
|
||||
REQUIRE(doc3.as<std::string>() == "{\"hello\":[]}");
|
||||
}
|
||||
|
||||
SECTION("destination is null") {
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
static void eraseString(std::string& str) {
|
||||
char* p = const_cast<char*>(str.c_str());
|
||||
while (*p)
|
||||
@ -20,7 +22,7 @@ TEST_CASE("std::string") {
|
||||
deserializeJson(doc, json);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
|
||||
REQUIRE(std::string("value") == obj[std::string("key")]);
|
||||
REQUIRE("value"_s == obj["key"_s]);
|
||||
}
|
||||
|
||||
SECTION("operator[] const") {
|
||||
@ -29,21 +31,14 @@ TEST_CASE("std::string") {
|
||||
deserializeJson(doc, json);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
|
||||
REQUIRE(std::string("value") == obj[std::string("key")]);
|
||||
}
|
||||
|
||||
SECTION("containsKey()") {
|
||||
char json[] = "{\"key\":\"value\"}";
|
||||
deserializeJson(doc, json);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
REQUIRE(true == obj.containsKey(std::string("key")));
|
||||
REQUIRE("value"_s == obj["key"_s]);
|
||||
}
|
||||
|
||||
SECTION("remove()") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["key"] = "value";
|
||||
|
||||
obj.remove(std::string("key"));
|
||||
obj.remove("key"_s);
|
||||
|
||||
REQUIRE(0 == obj.size());
|
||||
}
|
||||
@ -53,7 +48,7 @@ TEST_CASE("std::string") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj[key] = "world";
|
||||
eraseString(key);
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("operator[], set value") {
|
||||
@ -61,6 +56,6 @@ TEST_CASE("std::string") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = value;
|
||||
eraseString(value);
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonObject::operator[]") {
|
||||
SpyingAllocator spy;
|
||||
@ -50,7 +51,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
|
||||
REQUIRE(true == obj["hello"].is<const char*>());
|
||||
REQUIRE(false == obj["hello"].is<long>());
|
||||
REQUIRE(std::string("h3110") == obj["hello"].as<const char*>());
|
||||
REQUIRE("h3110"_s == obj["hello"].as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("array") {
|
||||
@ -117,22 +118,22 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
SECTION("should duplicate char* key") {
|
||||
obj[const_cast<char*>("hello")] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate char* key&value") {
|
||||
obj[const_cast<char*>("hello")] = const_cast<char*>("world");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string value") {
|
||||
obj["hello"] = std::string("world");
|
||||
obj["hello"] = "world"_s;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("world")),
|
||||
@ -140,18 +141,18 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string key") {
|
||||
obj[std::string("hello")] = "world";
|
||||
obj["hello"_s] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("should duplicate std::string key&value") {
|
||||
obj[std::string("hello")] = std::string("world");
|
||||
obj["hello"_s] = "world"_s;
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
@ -159,8 +160,8 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
SECTION("should duplicate a non-static JsonString key") {
|
||||
obj[JsonString("hello", JsonString::Copied)] = "world";
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
@ -197,7 +198,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
|
||||
obj[vla] = "world";
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("obj[str] = VLA") { // issue #416
|
||||
@ -207,7 +208,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
|
||||
obj["hello"] = vla;
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"].as<const char*>());
|
||||
REQUIRE("world"_s == obj["hello"].as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("obj.set(VLA, str)") {
|
||||
@ -217,7 +218,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
|
||||
obj[vla] = "world";
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("obj.set(str, VLA)") {
|
||||
@ -227,7 +228,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
|
||||
obj["hello"].set(vla);
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"].as<const char*>());
|
||||
REQUIRE("world"_s == obj["hello"].as<const char*>());
|
||||
}
|
||||
|
||||
SECTION("obj[VLA]") {
|
||||
@ -238,7 +239,7 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
|
||||
obj = doc.as<JsonObject>();
|
||||
REQUIRE(std::string("world") == obj[vla]);
|
||||
REQUIRE("world"_s == obj[vla]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -249,4 +250,18 @@ TEST_CASE("JsonObject::operator[]") {
|
||||
REQUIRE(true == obj["hello"]["world"].is<int>());
|
||||
REQUIRE(false == obj["hello"]["world"].is<bool>());
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
obj["hello"] = "world";
|
||||
obj["a\0b"_s] = "ABC";
|
||||
|
||||
doc["key1"] = "hello";
|
||||
doc["key2"] = "a\0b"_s;
|
||||
doc["key3"] = "foo";
|
||||
|
||||
REQUIRE(obj[obj["key1"]] == "world");
|
||||
REQUIRE(obj[obj["key2"]] == "ABC");
|
||||
REQUIRE(obj[obj["key3"]] == nullptr);
|
||||
REQUIRE(obj[obj["key4"]] == nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
# MIT License
|
||||
|
||||
add_executable(JsonObjectConstTests
|
||||
containsKey.cpp
|
||||
equals.cpp
|
||||
isNull.cpp
|
||||
iterator.cpp
|
||||
|
@ -1,32 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonObjectConst::containsKey()") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = 42;
|
||||
auto obj = doc.as<JsonObjectConst>();
|
||||
|
||||
SECTION("supports const char*") {
|
||||
REQUIRE(false == obj.containsKey("world"));
|
||||
REQUIRE(true == obj.containsKey("hello"));
|
||||
}
|
||||
|
||||
SECTION("supports std::string") {
|
||||
REQUIRE(false == obj.containsKey(std::string("world")));
|
||||
REQUIRE(true == obj.containsKey(std::string("hello")));
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == obj.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
}
|
@ -6,10 +6,12 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonObjectConst::operator[]") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = "world";
|
||||
doc["a\0b"_s] = "ABC";
|
||||
JsonObjectConst obj = doc.as<JsonObjectConst>();
|
||||
|
||||
SECTION("supports const char*") {
|
||||
@ -17,7 +19,8 @@ TEST_CASE("JsonObjectConst::operator[]") {
|
||||
}
|
||||
|
||||
SECTION("supports std::string") {
|
||||
REQUIRE(obj[std::string("hello")] == "world"); // issue #2019
|
||||
REQUIRE(obj["hello"_s] == "world"); // issue #2019
|
||||
REQUIRE(obj["a\0b"_s] == "ABC");
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
@ -27,7 +30,17 @@ TEST_CASE("JsonObjectConst::operator[]") {
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(std::string("world") == obj[vla]);
|
||||
REQUIRE(obj[vla] == "world"_s);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("supports JsonVariant") {
|
||||
doc["key1"] = "hello";
|
||||
doc["key2"] = "a\0b"_s;
|
||||
doc["key3"] = "foo";
|
||||
REQUIRE(obj[obj["key1"]] == "world");
|
||||
REQUIRE(obj[obj["key2"]] == "ABC");
|
||||
REQUIRE(obj[obj["key3"]] == nullptr);
|
||||
REQUIRE(obj[obj["key4"]] == nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
template <typename T>
|
||||
void check(T value, const std::string& expected) {
|
||||
JsonDocument doc;
|
||||
@ -30,42 +32,46 @@ TEST_CASE("serializeJson(JsonVariant)") {
|
||||
}
|
||||
|
||||
SECTION("string") {
|
||||
check(std::string("hello"), "\"hello\"");
|
||||
check("hello"_s, "\"hello\"");
|
||||
|
||||
SECTION("Escape quotation mark") {
|
||||
check(std::string("hello \"world\""), "\"hello \\\"world\\\"\"");
|
||||
check("hello \"world\""_s, "\"hello \\\"world\\\"\"");
|
||||
}
|
||||
|
||||
SECTION("Escape reverse solidus") {
|
||||
check(std::string("hello\\world"), "\"hello\\\\world\"");
|
||||
check("hello\\world"_s, "\"hello\\\\world\"");
|
||||
}
|
||||
|
||||
SECTION("Don't escape solidus") {
|
||||
check(std::string("fifty/fifty"), "\"fifty/fifty\"");
|
||||
check("fifty/fifty"_s, "\"fifty/fifty\"");
|
||||
}
|
||||
|
||||
SECTION("Don't escape single quote") {
|
||||
check("hello'world"_s, "\"hello'world\"");
|
||||
}
|
||||
|
||||
SECTION("Escape backspace") {
|
||||
check(std::string("hello\bworld"), "\"hello\\bworld\"");
|
||||
check("hello\bworld"_s, "\"hello\\bworld\"");
|
||||
}
|
||||
|
||||
SECTION("Escape formfeed") {
|
||||
check(std::string("hello\fworld"), "\"hello\\fworld\"");
|
||||
check("hello\fworld"_s, "\"hello\\fworld\"");
|
||||
}
|
||||
|
||||
SECTION("Escape linefeed") {
|
||||
check(std::string("hello\nworld"), "\"hello\\nworld\"");
|
||||
check("hello\nworld"_s, "\"hello\\nworld\"");
|
||||
}
|
||||
|
||||
SECTION("Escape carriage return") {
|
||||
check(std::string("hello\rworld"), "\"hello\\rworld\"");
|
||||
check("hello\rworld"_s, "\"hello\\rworld\"");
|
||||
}
|
||||
|
||||
SECTION("Escape tab") {
|
||||
check(std::string("hello\tworld"), "\"hello\\tworld\"");
|
||||
check("hello\tworld"_s, "\"hello\\tworld\"");
|
||||
}
|
||||
|
||||
SECTION("NUL char") {
|
||||
check(std::string("hello\0world", 11), "\"hello\\u0000world\"");
|
||||
check("hello\0world"_s, "\"hello\\u0000world\"");
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,13 +80,18 @@ TEST_CASE("serializeJson(JsonVariant)") {
|
||||
}
|
||||
|
||||
SECTION("SerializedValue<std::string>") {
|
||||
check(serialized(std::string("[1,2]")), "[1,2]");
|
||||
check(serialized("[1,2]"_s), "[1,2]");
|
||||
}
|
||||
|
||||
SECTION("Double") {
|
||||
check(3.1415927, "3.1415927");
|
||||
}
|
||||
|
||||
SECTION("Float") {
|
||||
REQUIRE(sizeof(float) == 4);
|
||||
check(3.1415927f, "3.141593");
|
||||
}
|
||||
|
||||
SECTION("Zero") {
|
||||
check(0, "0");
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("serialize JsonArray to std::string") {
|
||||
JsonDocument doc;
|
||||
JsonArray array = doc.to<JsonArray>();
|
||||
@ -48,7 +50,7 @@ TEST_CASE("serialize JsonObject to std::string") {
|
||||
|
||||
TEST_CASE("serialize an std::string containing a NUL") {
|
||||
JsonDocument doc;
|
||||
doc.set(std::string("hello\0world", 11));
|
||||
doc.set("hello\0world"_s);
|
||||
|
||||
std::string json = "erase me";
|
||||
serializeJson(doc, json);
|
||||
|
@ -7,7 +7,6 @@ add_executable(JsonVariantTests
|
||||
as.cpp
|
||||
clear.cpp
|
||||
compare.cpp
|
||||
containsKey.cpp
|
||||
converters.cpp
|
||||
copy.cpp
|
||||
is.cpp
|
||||
|
@ -6,6 +6,9 @@
|
||||
#include <stdint.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonVariant::add(T)") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
@ -23,7 +26,7 @@ TEST_CASE("JsonVariant::add(T)") {
|
||||
}
|
||||
|
||||
SECTION("add std::string to new variant") {
|
||||
var.add(std::string("hello"));
|
||||
var.add("hello"_s);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "[\"hello\"]");
|
||||
}
|
||||
@ -43,6 +46,18 @@ TEST_CASE("JsonVariant::add(T)") {
|
||||
|
||||
REQUIRE(var.as<std::string>() == "{\"val\":123}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLAs") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
var.add(vla);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "[\"hello\"]");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::add<T>()") {
|
||||
@ -56,15 +71,58 @@ TEST_CASE("JsonVariant::add<T>()") {
|
||||
REQUIRE(doc.as<std::string>() == "[[1,2]]");
|
||||
}
|
||||
|
||||
SECTION("JsonObject") {
|
||||
JsonObject object = var.add<JsonObject>();
|
||||
object["hello"] = "world";
|
||||
REQUIRE(doc.as<std::string>() == "[{\"hello\":\"world\"}]");
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
JsonVariant variant = var.add<JsonVariant>();
|
||||
variant.set(42);
|
||||
REQUIRE(doc.as<std::string>() == "[42]");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonObject::add(JsonObject) ") {
|
||||
JsonDocument doc1;
|
||||
doc1["hello"_s] = "world"_s;
|
||||
|
||||
TimebombAllocator allocator(10);
|
||||
SpyingAllocator spy(&allocator);
|
||||
JsonDocument doc2(&spy);
|
||||
JsonVariant variant = doc2.to<JsonVariant>();
|
||||
|
||||
SECTION("success") {
|
||||
bool result = variant.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc2.as<std::string>() == "[{\"hello\":\"world\"}]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
Allocate(sizeofString("world")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("partial failure") { // issue #2081
|
||||
allocator.setCountdown(2);
|
||||
|
||||
bool result = variant.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc2.as<std::string>() == "[]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Allocate(sizeofString("hello")),
|
||||
AllocateFail(sizeofString("world")),
|
||||
Deallocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("complete failure") {
|
||||
allocator.setCountdown(0);
|
||||
|
||||
bool result = variant.add(doc1.as<JsonObject>());
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc2.as<std::string>() == "[]");
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
AllocateFail(sizeofPool()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <stdint.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
namespace my {
|
||||
using ArduinoJson::detail::isinf;
|
||||
} // namespace my
|
||||
@ -25,17 +27,36 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(0 == variant.as<const char*>());
|
||||
REQUIRE("null" == variant.as<std::string>());
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(4.2)") {
|
||||
SECTION("set(float)") {
|
||||
variant.set(4.2f);
|
||||
|
||||
REQUIRE(variant.as<bool>());
|
||||
REQUIRE(0 == variant.as<const char*>());
|
||||
REQUIRE(variant.as<std::string>() == "4.2");
|
||||
REQUIRE(variant.as<long>() == 4L);
|
||||
REQUIRE(variant.as<float>() == 4.2f);
|
||||
REQUIRE(variant.as<unsigned>() == 4U);
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(double)") {
|
||||
variant.set(4.2);
|
||||
|
||||
REQUIRE(variant.as<bool>());
|
||||
REQUIRE(0 == variant.as<const char*>());
|
||||
REQUIRE(variant.as<std::string>() == "4.2");
|
||||
REQUIRE(variant.as<long>() == 4L);
|
||||
REQUIRE(variant.as<double>() == 4.2);
|
||||
REQUIRE(variant.as<unsigned>() == 4U);
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(0.0)") {
|
||||
@ -44,6 +65,8 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(variant.as<bool>() == false);
|
||||
REQUIRE(variant.as<long>() == 0L);
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(false)") {
|
||||
@ -54,6 +77,8 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(variant.as<long>() == 0L);
|
||||
REQUIRE(variant.as<std::string>() == "false");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(true)") {
|
||||
@ -64,43 +89,66 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(variant.as<long>() == 1L);
|
||||
REQUIRE(variant.as<std::string>() == "true");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(42)") {
|
||||
variant.set(42);
|
||||
SECTION("set(uint32_t)") {
|
||||
variant.set(4294967295U);
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<double>() == 42.0);
|
||||
REQUIRE(variant.as<int>() == 42);
|
||||
REQUIRE(variant.as<unsigned int>() == 42U); // issue #1601
|
||||
REQUIRE(variant.as<std::string>() == "42");
|
||||
REQUIRE(variant.as<double>() == 4294967295.0);
|
||||
REQUIRE(variant.as<int32_t>() == 0);
|
||||
REQUIRE(variant.as<uint32_t>() == 4294967295U);
|
||||
REQUIRE(variant.as<uint64_t>() == 4294967295U);
|
||||
REQUIRE(variant.as<std::string>() == "4294967295");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(42L)") {
|
||||
variant.set(42L);
|
||||
SECTION("set(int32_t)") {
|
||||
variant.set(-2147483648LL);
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<double>() == 42.0);
|
||||
REQUIRE(variant.as<std::string>() == "42");
|
||||
REQUIRE(variant.as<double>() == -2147483648LL);
|
||||
REQUIRE(variant.as<int32_t>() == -2147483648LL);
|
||||
REQUIRE(variant.as<int64_t>() == -2147483648LL);
|
||||
REQUIRE(variant.as<uint32_t>() == 0);
|
||||
REQUIRE(variant.as<uint64_t>() == 0);
|
||||
REQUIRE(variant.as<std::string>() == "-2147483648");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(-42L)") {
|
||||
variant.set(-42L);
|
||||
|
||||
REQUIRE(variant.as<double>() == -42.0);
|
||||
REQUIRE(variant.as<std::string>() == "-42");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
}
|
||||
|
||||
SECTION("set(42UL)") {
|
||||
variant.set(42UL);
|
||||
SECTION("set(uint64_t)") {
|
||||
variant.set(4294967296U);
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<double>() == 42.0);
|
||||
REQUIRE(variant.as<std::string>() == "42");
|
||||
REQUIRE(variant.as<double>() == 4294967296.0);
|
||||
REQUIRE(variant.as<int32_t>() == 0);
|
||||
REQUIRE(variant.as<uint32_t>() == 0);
|
||||
REQUIRE(variant.as<uint64_t>() == 4294967296U);
|
||||
REQUIRE(variant.as<std::string>() == "4294967296");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(int64_t)") {
|
||||
variant.set(-2147483649LL);
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<double>() == -2147483649LL);
|
||||
REQUIRE(variant.as<int32_t>() == 0);
|
||||
REQUIRE(variant.as<int64_t>() == -2147483649LL);
|
||||
REQUIRE(variant.as<uint32_t>() == 0);
|
||||
REQUIRE(variant.as<uint64_t>() == 0);
|
||||
REQUIRE(variant.as<std::string>() == "-2147483649");
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("set(0L)") {
|
||||
@ -144,20 +192,20 @@ TEST_CASE("JsonVariant::as()") {
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<long>() == 0L);
|
||||
REQUIRE(variant.as<const char*>() == std::string("hello"));
|
||||
REQUIRE(variant.as<const char*>() == std::string("hello"));
|
||||
REQUIRE(variant.as<std::string>() == std::string("hello"));
|
||||
REQUIRE(variant.as<const char*>() == "hello"_s);
|
||||
REQUIRE(variant.as<const char*>() == "hello"_s);
|
||||
REQUIRE(variant.as<std::string>() == "hello"_s);
|
||||
REQUIRE(variant.as<JsonString>() == "hello");
|
||||
}
|
||||
|
||||
SECTION("set(std::string(\"4.2\"))") {
|
||||
variant.set(std::string("4.2"));
|
||||
variant.set("4.2"_s);
|
||||
|
||||
REQUIRE(variant.as<bool>() == true);
|
||||
REQUIRE(variant.as<long>() == 4L);
|
||||
REQUIRE(variant.as<double>() == 4.2);
|
||||
REQUIRE(variant.as<const char*>() == std::string("4.2"));
|
||||
REQUIRE(variant.as<std::string>() == std::string("4.2"));
|
||||
REQUIRE(variant.as<double>() == Approx(4.2));
|
||||
REQUIRE(variant.as<const char*>() == "4.2"_s);
|
||||
REQUIRE(variant.as<std::string>() == "4.2"_s);
|
||||
REQUIRE(variant.as<JsonString>() == "4.2");
|
||||
REQUIRE(variant.as<JsonString>().isLinked() == false);
|
||||
}
|
||||
@ -199,6 +247,13 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(variant.as<JsonString>().isNull());
|
||||
}
|
||||
|
||||
SECTION("set(serialized(\"hello\"))") {
|
||||
variant.set(serialized("hello"));
|
||||
|
||||
REQUIRE(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
REQUIRE(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
}
|
||||
|
||||
SECTION("to<JsonObject>()") {
|
||||
JsonObject obj = variant.to<JsonObject>();
|
||||
obj["key"] = "value";
|
||||
@ -208,13 +263,13 @@ TEST_CASE("JsonVariant::as()") {
|
||||
}
|
||||
|
||||
SECTION("as<std::string>()") {
|
||||
REQUIRE(variant.as<std::string>() == std::string("{\"key\":\"value\"}"));
|
||||
REQUIRE(variant.as<std::string>() == "{\"key\":\"value\"}"_s);
|
||||
}
|
||||
|
||||
SECTION("ObjectAsJsonObject") {
|
||||
JsonObject o = variant.as<JsonObject>();
|
||||
REQUIRE(o.size() == 1);
|
||||
REQUIRE(o["key"] == std::string("value"));
|
||||
REQUIRE(o["key"] == "value"_s);
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,7 +283,7 @@ TEST_CASE("JsonVariant::as()") {
|
||||
}
|
||||
|
||||
SECTION("as<std::string>()") {
|
||||
REQUIRE(variant.as<std::string>() == std::string("[4,2]"));
|
||||
REQUIRE(variant.as<std::string>() == "[4,2]"_s);
|
||||
}
|
||||
|
||||
SECTION("as<JsonArray>()") {
|
||||
@ -245,7 +300,7 @@ TEST_CASE("JsonVariant::as()") {
|
||||
REQUIRE(variant.as<long long>() == -9223372036854775807 - 1);
|
||||
}
|
||||
|
||||
SECTION("Biggerst int64 positive") {
|
||||
SECTION("Biggest int64 positive") {
|
||||
variant.set("9223372036854775807");
|
||||
REQUIRE(variant.as<long long>() == 9223372036854775807);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonVariant::clear()") {
|
||||
SpyingAllocator spy;
|
||||
@ -28,7 +29,7 @@ TEST_CASE("JsonVariant::clear()") {
|
||||
}
|
||||
|
||||
SECTION("releases owned string") {
|
||||
var.set(std::string("hello"));
|
||||
var.set("hello"_s);
|
||||
var.clear();
|
||||
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
|
@ -113,6 +113,42 @@ TEST_CASE("Compare JsonVariant with JsonVariant") {
|
||||
CHECK_FALSE(a == b);
|
||||
}
|
||||
|
||||
SECTION("MsgPackBinary('abc') vs MsgPackBinary('abc')") {
|
||||
a.set(MsgPackBinary("abc", 4));
|
||||
b.set(MsgPackBinary("abc", 4));
|
||||
|
||||
CHECK(a == b);
|
||||
CHECK(a <= b);
|
||||
CHECK(a >= b);
|
||||
CHECK_FALSE(a != b);
|
||||
CHECK_FALSE(a < b);
|
||||
CHECK_FALSE(a > b);
|
||||
}
|
||||
|
||||
SECTION("MsgPackBinary('abc') vs MsgPackBinary('bcd')") {
|
||||
a.set(MsgPackBinary("abc", 4));
|
||||
b.set(MsgPackBinary("bcd", 4));
|
||||
|
||||
CHECK(a != b);
|
||||
CHECK(a < b);
|
||||
CHECK(a <= b);
|
||||
CHECK_FALSE(a == b);
|
||||
CHECK_FALSE(a > b);
|
||||
CHECK_FALSE(a >= b);
|
||||
}
|
||||
|
||||
SECTION("MsgPackBinary('bcd') vs MsgPackBinary('abc')") {
|
||||
a.set(MsgPackBinary("bcd", 4));
|
||||
b.set(MsgPackBinary("abc", 4));
|
||||
|
||||
CHECK(a != b);
|
||||
CHECK(a > b);
|
||||
CHECK(a >= b);
|
||||
CHECK_FALSE(a < b);
|
||||
CHECK_FALSE(a <= b);
|
||||
CHECK_FALSE(a == b);
|
||||
}
|
||||
|
||||
SECTION("false vs true") {
|
||||
a.set(false);
|
||||
b.set(true);
|
||||
|
@ -1,26 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <stdint.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonVariant::containsKey()") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("containsKey(const char*)") {
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(var.containsKey("hello") == true);
|
||||
REQUIRE(var.containsKey("world") == false);
|
||||
}
|
||||
|
||||
SECTION("containsKey(std::string)") {
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(var.containsKey(std::string("hello")) == true);
|
||||
REQUIRE(var.containsKey(std::string("world")) == false);
|
||||
}
|
||||
}
|
@ -140,15 +140,3 @@ TEST_CASE("Custom converter with specialization") {
|
||||
REQUIRE(doc["value"]["imag"] == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("ConverterNeedsWriteableRef") {
|
||||
using namespace ArduinoJson::detail;
|
||||
CHECK(ConverterNeedsWriteableRef<int>::value == false);
|
||||
CHECK(ConverterNeedsWriteableRef<float>::value == false);
|
||||
CHECK(ConverterNeedsWriteableRef<JsonVariant>::value == true);
|
||||
CHECK(ConverterNeedsWriteableRef<JsonVariantConst>::value == false);
|
||||
CHECK(ConverterNeedsWriteableRef<JsonObject>::value == true);
|
||||
CHECK(ConverterNeedsWriteableRef<JsonObjectConst>::value == false);
|
||||
CHECK(ConverterNeedsWriteableRef<JsonArray>::value == true);
|
||||
CHECK(ConverterNeedsWriteableRef<JsonArrayConst>::value == false);
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <catch.hpp>
|
||||
#include "Allocators.hpp"
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
KillswitchAllocator killswitch;
|
||||
SpyingAllocator spyingAllocator(&killswitch);
|
||||
@ -72,7 +74,7 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
}
|
||||
|
||||
SECTION("stores std::string by copy") {
|
||||
var1.set(std::string("hello!!"));
|
||||
var1.set("hello!!"_s);
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
@ -106,7 +108,7 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
}
|
||||
|
||||
SECTION("stores Serialized<std::string> by copy") {
|
||||
var1.set(serialized(std::string("hello!!")));
|
||||
var1.set(serialized("hello!!"_s));
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
var2.set(var1);
|
||||
@ -117,7 +119,7 @@ TEST_CASE("JsonVariant::set(JsonVariant)") {
|
||||
}
|
||||
|
||||
SECTION("fails gracefully if raw string allocation fails") {
|
||||
var1.set(serialized(std::string("hello!!")));
|
||||
var1.set(serialized("hello!!"_s));
|
||||
killswitch.on();
|
||||
spyingAllocator.clearLog();
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofArray;
|
||||
|
||||
@ -15,9 +16,9 @@ TEST_CASE("JsonVariant::remove(int)") {
|
||||
JsonDocument doc(&spy);
|
||||
|
||||
SECTION("release top level strings") {
|
||||
doc.add(std::string("hello"));
|
||||
doc.add(std::string("hello"));
|
||||
doc.add(std::string("world"));
|
||||
doc.add("hello"_s);
|
||||
doc.add("hello"_s);
|
||||
doc.add("world"_s);
|
||||
|
||||
JsonVariant var = doc.as<JsonVariant>();
|
||||
REQUIRE(var.as<std::string>() == "[\"hello\",\"hello\",\"world\"]");
|
||||
@ -43,7 +44,7 @@ TEST_CASE("JsonVariant::remove(int)") {
|
||||
}
|
||||
|
||||
SECTION("release strings in nested array") {
|
||||
doc[0][0] = std::string("hello");
|
||||
doc[0][0] = "hello"_s;
|
||||
|
||||
JsonVariant var = doc.as<JsonVariant>();
|
||||
REQUIRE(var.as<std::string>() == "[[\"hello\"]]");
|
||||
@ -77,7 +78,51 @@ TEST_CASE("JsonVariant::remove(std::string)") {
|
||||
var["a"] = 1;
|
||||
var["b"] = 2;
|
||||
|
||||
var.remove(std::string("b"));
|
||||
var.remove("b"_s);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
TEST_CASE("JsonVariant::remove(VLA)") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
var["a"] = 1;
|
||||
var["b"] = 2;
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "b");
|
||||
|
||||
var.remove("b"_s);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "{\"a\":1}");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("JsonVariant::remove(JsonVariant) from object") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
var["a"] = "a";
|
||||
var["b"] = 2;
|
||||
var["c"] = "b";
|
||||
|
||||
var.remove(var["c"]);
|
||||
|
||||
REQUIRE(var.as<std::string>() == "{\"a\":\"a\",\"c\":\"b\"}");
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::remove(JsonVariant) from array") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
|
||||
var[0] = 3;
|
||||
var[1] = 2;
|
||||
var[2] = 1;
|
||||
|
||||
var.remove(var[2]);
|
||||
var.remove(var[3]); // noop
|
||||
|
||||
REQUIRE(var.as<std::string>() == "[3,1]");
|
||||
}
|
||||
|
@ -6,13 +6,15 @@
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Allocators.hpp"
|
||||
#include "Literals.hpp"
|
||||
|
||||
using ArduinoJson::detail::sizeofObject;
|
||||
|
||||
enum ErrorCode { ERROR_01 = 1, ERROR_10 = 10 };
|
||||
|
||||
TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
JsonDocument doc;
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("const char*") {
|
||||
@ -24,6 +26,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "world"); // stores by pointer
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("(const char*)0") {
|
||||
@ -31,6 +34,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.isNull());
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("char*") {
|
||||
@ -42,6 +46,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("(char*)0") {
|
||||
@ -49,6 +56,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.isNull());
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("unsigned char*") {
|
||||
@ -60,6 +68,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("signed char*") {
|
||||
@ -71,6 +82,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
@ -84,6 +98,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -96,6 +113,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("static JsonString") {
|
||||
@ -107,6 +127,7 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "world"); // stores by pointer
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("non-static JsonString") {
|
||||
@ -118,6 +139,9 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant == "hello"); // stores by copy
|
||||
REQUIRE(spy.log() == AllocatorLog{
|
||||
Allocate(sizeofString("hello")),
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("enum") {
|
||||
@ -128,6 +152,89 @@ TEST_CASE("JsonVariant::set() when there is enough memory") {
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<int>() == true);
|
||||
REQUIRE(variant.as<int>() == 10);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("float") {
|
||||
bool result = variant.set(1.2f);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<float>() == true);
|
||||
REQUIRE(variant.as<float>() == 1.2f);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("double") {
|
||||
bool result = variant.set(1.2);
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<double>() == true);
|
||||
REQUIRE(variant.as<double>() == 1.2);
|
||||
REQUIRE(spy.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("int32_t") {
|
||||
bool result = variant.set(int32_t(42));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<int32_t>() == true);
|
||||
REQUIRE(variant.as<int32_t>() == 42);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("int64_t") {
|
||||
bool result = variant.set(int64_t(-2147483649LL));
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<int64_t>() == true);
|
||||
REQUIRE(variant.as<int64_t>() == -2147483649LL);
|
||||
REQUIRE(spy.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("uint32_t") {
|
||||
bool result = variant.set(uint32_t(42));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<uint32_t>() == true);
|
||||
REQUIRE(variant.as<uint32_t>() == 42);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("uint64_t") {
|
||||
bool result = variant.set(uint64_t(4294967296));
|
||||
doc.shrinkToFit();
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(variant.is<uint64_t>() == true);
|
||||
REQUIRE(variant.as<uint64_t>() == 4294967296);
|
||||
REQUIRE(spy.log() ==
|
||||
AllocatorLog{
|
||||
Allocate(sizeofPool()),
|
||||
Reallocate(sizeofPool(), sizeofPool(1)), // one extension slot
|
||||
});
|
||||
}
|
||||
|
||||
SECTION("JsonDocument") {
|
||||
JsonDocument doc1;
|
||||
doc1["hello"] = "world";
|
||||
|
||||
// Should copy the doc
|
||||
variant.set(doc1);
|
||||
doc1.clear();
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc, json);
|
||||
REQUIRE(json == "{\"hello\":\"world\"}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,14 +244,14 @@ TEST_CASE("JsonVariant::set() with not enough memory") {
|
||||
JsonVariant v = doc.to<JsonVariant>();
|
||||
|
||||
SECTION("std::string") {
|
||||
bool result = v.set(std::string("hello world!!"));
|
||||
bool result = v.set("hello world!!"_s);
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(v.isNull());
|
||||
}
|
||||
|
||||
SECTION("Serialized<std::string>") {
|
||||
bool result = v.set(serialized(std::string("hello world!!")));
|
||||
bool result = v.set(serialized("hello world!!"_s));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(v.isNull());
|
||||
@ -157,28 +264,54 @@ TEST_CASE("JsonVariant::set() with not enough memory") {
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(v.isNull());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::set(JsonDocument)") {
|
||||
JsonDocument doc1;
|
||||
doc1["hello"] = "world";
|
||||
SECTION("float") {
|
||||
bool result = v.set(1.2f);
|
||||
|
||||
JsonDocument doc2;
|
||||
JsonVariant v = doc2.to<JsonVariant>();
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(v.is<float>());
|
||||
}
|
||||
|
||||
// Should copy the doc
|
||||
v.set(doc1);
|
||||
doc1.clear();
|
||||
SECTION("double") {
|
||||
bool result = v.set(1.2);
|
||||
|
||||
std::string json;
|
||||
serializeJson(doc2, json);
|
||||
REQUIRE(json == "{\"hello\":\"world\"}");
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(v.isNull());
|
||||
}
|
||||
|
||||
SECTION("int32_t") {
|
||||
bool result = v.set(-42);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(v.is<int32_t>());
|
||||
}
|
||||
|
||||
SECTION("int64_t") {
|
||||
bool result = v.set(-2147483649LL);
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(v.isNull());
|
||||
}
|
||||
|
||||
SECTION("uint32_t") {
|
||||
bool result = v.set(42);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(v.is<uint32_t>());
|
||||
}
|
||||
|
||||
SECTION("uint64_t") {
|
||||
bool result = v.set(4294967296U);
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(v.isNull());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::set() releases the previous value") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
doc["hello"] = std::string("world");
|
||||
doc["hello"] = "world"_s;
|
||||
spy.clearLog();
|
||||
|
||||
JsonVariant v = doc["hello"];
|
||||
@ -219,3 +352,34 @@ TEST_CASE("JsonVariant::set() releases the previous value") {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("JsonVariant::set() reuses extension slot") {
|
||||
SpyingAllocator spy;
|
||||
JsonDocument doc(&spy);
|
||||
JsonVariant variant = doc.to<JsonVariant>();
|
||||
|
||||
variant.set(1.2);
|
||||
doc.shrinkToFit();
|
||||
spy.clearLog();
|
||||
|
||||
SECTION("double") {
|
||||
bool result = variant.set(3.4);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("int64_t") {
|
||||
bool result = variant.set(-2147483649LL);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
|
||||
SECTION("uint64_t") {
|
||||
bool result = variant.set(4294967296U);
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(spy.log() == AllocatorLog{});
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ TEST_CASE("vector<int>") {
|
||||
}
|
||||
|
||||
TEST_CASE("array<int, 2>") {
|
||||
typedef std::array<int, 2> array_type;
|
||||
using array_type = std::array<int, 2>;
|
||||
|
||||
SECTION("toJson") {
|
||||
array_type v;
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonVariant::operator[]") {
|
||||
JsonDocument doc;
|
||||
JsonVariant var = doc.to<JsonVariant>();
|
||||
@ -31,9 +33,9 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
|
||||
REQUIRE(2 == var.size());
|
||||
var[0].as<std::string>();
|
||||
// REQUIRE(std::string("element at index 0") == );
|
||||
REQUIRE(std::string("element at index 1") == var[1]);
|
||||
REQUIRE(std::string("element at index 0") ==
|
||||
// REQUIRE("element at index 0"_s == );
|
||||
REQUIRE("element at index 1"_s == var[1]);
|
||||
REQUIRE("element at index 0"_s ==
|
||||
var[static_cast<unsigned char>(0)]); // issue #381
|
||||
REQUIRE(var[666].isNull());
|
||||
REQUIRE(var[3].isNull());
|
||||
@ -46,7 +48,7 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
var[1] = "world";
|
||||
|
||||
REQUIRE(var.size() == 2);
|
||||
REQUIRE(std::string("world") == var[1]);
|
||||
REQUIRE("world"_s == var[1]);
|
||||
}
|
||||
|
||||
SECTION("set value in a nested object") {
|
||||
@ -56,7 +58,7 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
|
||||
REQUIRE(1 == var.size());
|
||||
REQUIRE(1 == var[0].size());
|
||||
REQUIRE(std::string("world") == var[0]["hello"]);
|
||||
REQUIRE("world"_s == var[0]["hello"]);
|
||||
}
|
||||
|
||||
SECTION("variant[0] when variant contains an integer") {
|
||||
@ -67,6 +69,15 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
REQUIRE(var.is<int>());
|
||||
REQUIRE(var.as<int>() == 123);
|
||||
}
|
||||
|
||||
SECTION("use JsonVariant as index") {
|
||||
array.add("A");
|
||||
array.add("B");
|
||||
array.add(1);
|
||||
|
||||
REQUIRE(var[var[2]] == "B");
|
||||
REQUIRE(var[var[3]].isNull());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("The JsonVariant is a JsonObject") {
|
||||
@ -77,8 +88,8 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
object["b"] = "element at key \"b\"";
|
||||
|
||||
REQUIRE(2 == var.size());
|
||||
REQUIRE(std::string("element at key \"a\"") == var["a"]);
|
||||
REQUIRE(std::string("element at key \"b\"") == var["b"]);
|
||||
REQUIRE("element at key \"a\""_s == var["a"]);
|
||||
REQUIRE("element at key \"b\""_s == var["b"]);
|
||||
REQUIRE(var["c"].isNull());
|
||||
REQUIRE(var[0].isNull());
|
||||
}
|
||||
@ -87,7 +98,7 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
var["hello"] = "world";
|
||||
|
||||
REQUIRE(1 == var.size());
|
||||
REQUIRE(std::string("world") == var["hello"]);
|
||||
REQUIRE("world"_s == var["hello"]);
|
||||
}
|
||||
|
||||
SECTION("set value, key is a char[]") {
|
||||
@ -96,13 +107,29 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
key[0] = '!'; // make sure the key is duplicated
|
||||
|
||||
REQUIRE(1 == var.size());
|
||||
REQUIRE(std::string("world") == var["hello"]);
|
||||
REQUIRE("world"_s == var["hello"]);
|
||||
}
|
||||
|
||||
SECTION("var[key].to<JsonArray>()") {
|
||||
JsonArray arr = var["hello"].to<JsonArray>();
|
||||
REQUIRE(arr.isNull() == false);
|
||||
}
|
||||
|
||||
SECTION("use JsonVariant as key") {
|
||||
object["a"] = "A";
|
||||
object["ab"] = "AB";
|
||||
object["ab\0c"_s] = "ABC";
|
||||
object["key1"] = "a";
|
||||
object["key2"] = "ab";
|
||||
object["key3"] = "ab\0c"_s;
|
||||
object["key4"] = "foo";
|
||||
|
||||
REQUIRE(var[var["key1"]] == "A");
|
||||
REQUIRE(var[var["key2"]] == "AB");
|
||||
REQUIRE(var[var["key3"]] == "ABC");
|
||||
REQUIRE(var[var["key4"]].isNull());
|
||||
REQUIRE(var[var["key5"]].isNull());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
@ -115,7 +142,7 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[vla]);
|
||||
REQUIRE("world"_s == variant[vla]);
|
||||
}
|
||||
|
||||
SECTION("key is a VLA, const JsonVariant") {
|
||||
@ -126,7 +153,7 @@ TEST_CASE("JsonVariant::operator[]") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
const JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[vla]);
|
||||
REQUIRE("world"_s == variant[vla]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("Unbound JsonVariant") {
|
||||
JsonVariant variant;
|
||||
|
||||
@ -21,6 +23,10 @@ TEST_CASE("Unbound JsonVariant") {
|
||||
CHECK(variant.as<JsonObject>().isNull());
|
||||
CHECK(variant.as<JsonObjectConst>().isNull());
|
||||
CHECK(variant.as<JsonString>().isNull());
|
||||
CHECK(variant.as<MsgPackBinary>().data() == nullptr);
|
||||
CHECK(variant.as<MsgPackBinary>().size() == 0);
|
||||
CHECK(variant.as<MsgPackExtension>().data() == nullptr);
|
||||
CHECK(variant.as<MsgPackExtension>().size() == 0);
|
||||
}
|
||||
|
||||
SECTION("is<T>()") {
|
||||
@ -44,8 +50,10 @@ TEST_CASE("Unbound JsonVariant") {
|
||||
CHECK_FALSE(variant.set(42L));
|
||||
CHECK_FALSE(variant.set(42U));
|
||||
CHECK_FALSE(variant.set(serialized("42")));
|
||||
CHECK_FALSE(variant.set(serialized(std::string("42"))));
|
||||
CHECK_FALSE(variant.set(serialized("42"_s)));
|
||||
CHECK_FALSE(variant.set(true));
|
||||
CHECK_FALSE(variant.set(MsgPackBinary("hello", 5)));
|
||||
CHECK_FALSE(variant.set(MsgPackExtension(1, "hello", 5)));
|
||||
}
|
||||
|
||||
SECTION("add()") {
|
||||
@ -62,11 +70,7 @@ TEST_CASE("Unbound JsonVariant") {
|
||||
CHECK(variant["key"].isNull());
|
||||
CHECK_FALSE(variant[0].set(1));
|
||||
CHECK_FALSE(variant["key"].set(1));
|
||||
CHECK_FALSE(variant[std::string("key")].set(1));
|
||||
}
|
||||
|
||||
SECTION("containsKey()") {
|
||||
CHECK_FALSE(variant.containsKey("hello"));
|
||||
CHECK_FALSE(variant["key"_s].set(1));
|
||||
}
|
||||
|
||||
SECTION("remove()") {
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
add_executable(JsonVariantConstTests
|
||||
as.cpp
|
||||
containsKey.cpp
|
||||
is.cpp
|
||||
isnull.cpp
|
||||
nesting.cpp
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <stdint.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonVariantConst::as<T>()") {
|
||||
JsonDocument doc;
|
||||
JsonVariantConst var = doc.to<JsonVariant>();
|
||||
@ -14,6 +16,27 @@ TEST_CASE("JsonVariantConst::as<T>()") {
|
||||
|
||||
REQUIRE(var.as<bool>() == true);
|
||||
REQUIRE(var.as<long>() == 0L);
|
||||
REQUIRE(var.as<const char*>() == std::string("hello"));
|
||||
REQUIRE(var.as<std::string>() == std::string("hello"));
|
||||
REQUIRE(var.as<const char*>() == "hello"_s);
|
||||
REQUIRE(var.as<std::string>() == "hello"_s);
|
||||
}
|
||||
|
||||
TEST_CASE("Invalid conversions") {
|
||||
using namespace ArduinoJson::detail;
|
||||
|
||||
JsonVariantConst variant;
|
||||
|
||||
CHECK(is_same<decltype(variant.as<int>()), int>::value);
|
||||
CHECK(is_same<decltype(variant.as<float>()), float>::value);
|
||||
CHECK(is_same<decltype(variant.as<JsonVariantConst>()),
|
||||
JsonVariantConst>::value);
|
||||
CHECK(
|
||||
is_same<decltype(variant.as<JsonObjectConst>()), JsonObjectConst>::value);
|
||||
CHECK(is_same<decltype(variant.as<JsonArrayConst>()), JsonArrayConst>::value);
|
||||
|
||||
CHECK(is_same<decltype(variant.as<JsonVariant>()),
|
||||
InvalidConversion<JsonVariantConst, JsonVariant>>::value);
|
||||
CHECK(is_same<decltype(variant.as<JsonObject>()),
|
||||
InvalidConversion<JsonVariantConst, JsonObject>>::value);
|
||||
CHECK(is_same<decltype(variant.as<JsonArray>()),
|
||||
InvalidConversion<JsonVariantConst, JsonArray>>::value);
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <stdint.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("JsonVariantConst::containsKey()") {
|
||||
JsonDocument doc;
|
||||
doc["hello"] = "world";
|
||||
JsonVariantConst var = doc.as<JsonVariant>();
|
||||
|
||||
SECTION("support const char*") {
|
||||
REQUIRE(var.containsKey("hello") == true);
|
||||
REQUIRE(var.containsKey("world") == false);
|
||||
}
|
||||
|
||||
SECTION("support std::string") {
|
||||
REQUIRE(var.containsKey(std::string("hello")) == true);
|
||||
REQUIRE(var.containsKey(std::string("world")) == false);
|
||||
}
|
||||
|
||||
#ifdef HAS_VARIABLE_LENGTH_ARRAY
|
||||
SECTION("supports VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "hello");
|
||||
|
||||
REQUIRE(true == var.containsKey(vla));
|
||||
}
|
||||
#endif
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("JsonVariantConst::operator[]") {
|
||||
JsonDocument doc;
|
||||
JsonVariantConst var = doc.to<JsonVariant>();
|
||||
@ -27,31 +29,43 @@ TEST_CASE("JsonVariantConst::operator[]") {
|
||||
array.add("A");
|
||||
array.add("B");
|
||||
|
||||
REQUIRE(std::string("A") == var[0]);
|
||||
REQUIRE(std::string("B") == var[1]);
|
||||
REQUIRE(std::string("A") ==
|
||||
var[static_cast<unsigned char>(0)]); // issue #381
|
||||
REQUIRE(var[666].isNull());
|
||||
REQUIRE(var[3].isNull());
|
||||
REQUIRE(var["0"].isNull());
|
||||
SECTION("int") {
|
||||
REQUIRE("A"_s == var[0]);
|
||||
REQUIRE("B"_s == var[1]);
|
||||
REQUIRE("A"_s == var[static_cast<unsigned char>(0)]); // issue #381
|
||||
REQUIRE(var[666].isNull());
|
||||
REQUIRE(var[3].isNull());
|
||||
}
|
||||
|
||||
SECTION("const char*") {
|
||||
REQUIRE(var["0"].isNull());
|
||||
}
|
||||
|
||||
SECTION("JsonVariant") {
|
||||
array.add(1);
|
||||
REQUIRE(var[var[2]] == "B"_s);
|
||||
REQUIRE(var[var[3]].isNull());
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object") {
|
||||
JsonObject object = doc.to<JsonObject>();
|
||||
object["a"] = "A";
|
||||
object["b"] = "B";
|
||||
object["ab"_s] = "AB";
|
||||
object["abc"_s] = "ABC";
|
||||
object["abc\0d"_s] = "ABCD";
|
||||
|
||||
SECTION("supports const char*") {
|
||||
REQUIRE(std::string("A") == var["a"]);
|
||||
REQUIRE(std::string("B") == var["b"]);
|
||||
REQUIRE(var["c"].isNull());
|
||||
REQUIRE(var["ab"] == "AB"_s);
|
||||
REQUIRE(var["abc"] == "ABC"_s);
|
||||
REQUIRE(var["def"].isNull());
|
||||
REQUIRE(var[0].isNull());
|
||||
}
|
||||
|
||||
SECTION("supports std::string") {
|
||||
REQUIRE(std::string("A") == var[std::string("a")]);
|
||||
REQUIRE(std::string("B") == var[std::string("b")]);
|
||||
REQUIRE(var[std::string("c")].isNull());
|
||||
REQUIRE(var["ab"_s] == "AB"_s);
|
||||
REQUIRE(var["abc"_s] == "ABC"_s);
|
||||
REQUIRE(var["abc\0d"_s] == "ABCD"_s);
|
||||
REQUIRE(var["def"_s].isNull());
|
||||
}
|
||||
|
||||
#if defined(HAS_VARIABLE_LENGTH_ARRAY) && \
|
||||
@ -59,10 +73,23 @@ TEST_CASE("JsonVariantConst::operator[]") {
|
||||
SECTION("supports VLA") {
|
||||
size_t i = 16;
|
||||
char vla[i];
|
||||
strcpy(vla, "a");
|
||||
strcpy(vla, "abc");
|
||||
|
||||
REQUIRE(std::string("A") == var[vla]);
|
||||
REQUIRE(var[vla] == "ABC"_s);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("supports JsonVariant") {
|
||||
object["key1"] = "ab";
|
||||
object["key2"] = "abc";
|
||||
object["key3"] = "abc\0d"_s;
|
||||
object["key4"] = "foo";
|
||||
|
||||
REQUIRE(var[var["key1"]] == "AB"_s);
|
||||
REQUIRE(var[var["key2"]] == "ABC"_s);
|
||||
REQUIRE(var[var["key3"]] == "ABCD"_s);
|
||||
REQUIRE(var[var["key4"]].isNull());
|
||||
REQUIRE(var[var["key5"]].isNull());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
add_executable(MiscTests
|
||||
arithmeticCompare.cpp
|
||||
conflicts.cpp
|
||||
FloatParts.cpp
|
||||
issue1967.cpp
|
||||
issue2129.cpp
|
||||
JsonString.cpp
|
||||
NoArduinoHeader.cpp
|
||||
printable.cpp
|
||||
|
@ -12,77 +12,101 @@
|
||||
#include "custom_string.hpp"
|
||||
#include "weird_strcmp.hpp"
|
||||
|
||||
using ArduinoJson::JsonString;
|
||||
using namespace ArduinoJson::detail;
|
||||
|
||||
TEST_CASE("ZeroTerminatedRamString") {
|
||||
SECTION("null") {
|
||||
ZeroTerminatedRamString s = adaptString(static_cast<const char*>(0));
|
||||
TEST_CASE("adaptString()") {
|
||||
SECTION("null const char*") {
|
||||
auto s = adaptString(static_cast<const char*>(0));
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.size() == 0);
|
||||
CHECK(s.isLinked() == true);
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
ZeroTerminatedRamString s = adaptString("bravo");
|
||||
SECTION("non-null const char*") {
|
||||
auto s = adaptString("bravo");
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("SizedRamString") {
|
||||
SECTION("null") {
|
||||
SizedRamString s = adaptString(static_cast<const char*>(0), 10);
|
||||
SECTION("null const char* + size") {
|
||||
auto s = adaptString(static_cast<const char*>(0), 10);
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
SizedRamString s = adaptString("bravo", 5);
|
||||
SECTION("non-null const char* + size") {
|
||||
auto s = adaptString("bravo", 5);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("FlashString") {
|
||||
SECTION("null") {
|
||||
FlashString s = adaptString(static_cast<const __FlashStringHelper*>(0));
|
||||
SECTION("null Flash string") {
|
||||
auto s = adaptString(static_cast<const __FlashStringHelper*>(0));
|
||||
|
||||
CHECK(s.isNull() == true);
|
||||
CHECK(s.size() == 0);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
|
||||
SECTION("non-null") {
|
||||
FlashString s = adaptString(F("bravo"));
|
||||
SECTION("non-null Flash string") {
|
||||
auto s = adaptString(F("bravo"));
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("std::string") {
|
||||
std::string orig("bravo");
|
||||
SizedRamString s = adaptString(orig);
|
||||
SECTION("std::string") {
|
||||
std::string orig("bravo");
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
}
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("Arduino String") {
|
||||
::String orig("bravo");
|
||||
SizedRamString s = adaptString(orig);
|
||||
SECTION("Arduino String") {
|
||||
::String orig("bravo");
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
}
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_string") {
|
||||
custom_string orig("bravo");
|
||||
SizedRamString s = adaptString(orig);
|
||||
SECTION("custom_string") {
|
||||
custom_string orig("bravo");
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
|
||||
SECTION("JsonString linked") {
|
||||
JsonString orig("hello", JsonString::Ownership::Linked);
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == true);
|
||||
}
|
||||
|
||||
SECTION("JsonString copied") {
|
||||
JsonString orig("hello", JsonString::Ownership::Copied);
|
||||
auto s = adaptString(orig);
|
||||
|
||||
CHECK(s.isNull() == false);
|
||||
CHECK(s.size() == 5);
|
||||
CHECK(s.isLinked() == false);
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyStruct {};
|
||||
@ -97,6 +121,7 @@ TEST_CASE("IsString<T>") {
|
||||
CHECK(IsString<::String>::value == true);
|
||||
CHECK(IsString<::StringSumHelper>::value == true);
|
||||
CHECK(IsString<const EmptyStruct*>::value == false);
|
||||
CHECK(IsString<JsonString>::value == true);
|
||||
}
|
||||
|
||||
TEST_CASE("stringCompare") {
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
#include "custom_string.hpp"
|
||||
|
||||
using namespace ArduinoJson::detail;
|
||||
@ -36,13 +37,13 @@ void common_tests(StringWriter& writer, const String& output) {
|
||||
|
||||
SECTION("OneString") {
|
||||
REQUIRE(4 == print(writer, "ABCD"));
|
||||
REQUIRE(std::string("ABCD") == output);
|
||||
REQUIRE("ABCD"_s == output);
|
||||
}
|
||||
|
||||
SECTION("TwoStrings") {
|
||||
REQUIRE(4 == print(writer, "ABCD"));
|
||||
REQUIRE(4 == print(writer, "EFGH"));
|
||||
REQUIRE(std::string("ABCDEFGH") == output);
|
||||
REQUIRE("ABCDEFGH"_s == output);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,5 +58,10 @@
|
||||
// issue #1914
|
||||
#define V7 7
|
||||
|
||||
// STM32, Mbed, Particle
|
||||
#define A0 16
|
||||
#define A1 17
|
||||
#define A2 18
|
||||
|
||||
// catch.hpp mutes several warnings, this file also allows to detect them
|
||||
#include "ArduinoJson.h"
|
||||
|
@ -7,6 +7,5 @@
|
||||
#include <string>
|
||||
|
||||
struct custom_char_traits : std::char_traits<char> {};
|
||||
struct custom_allocator : std::allocator<char> {};
|
||||
typedef std::basic_string<char, custom_char_traits, custom_allocator>
|
||||
custom_string;
|
||||
|
||||
using custom_string = std::basic_string<char, custom_char_traits>;
|
||||
|
55
extras/tests/Misc/issue2129.cpp
Normal file
55
extras/tests/Misc/issue2129.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
// ArduinoJson - https://arduinojson.org
|
||||
// Copyright © 2014-2024, Benoit BLANCHON
|
||||
// MIT License
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
template <typename T>
|
||||
class Nullable {
|
||||
public:
|
||||
Nullable() : value_{} {}
|
||||
Nullable(T value) : value_{value} {}
|
||||
|
||||
operator T() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
operator T&() {
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool is_valid() const {
|
||||
return value_ != invalid_value_;
|
||||
}
|
||||
|
||||
T value() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
static T invalid_value_;
|
||||
};
|
||||
|
||||
template <>
|
||||
float Nullable<float>::invalid_value_ = std::numeric_limits<float>::lowest();
|
||||
|
||||
template <typename T>
|
||||
void convertToJson(const Nullable<T>& src, JsonVariant dst) {
|
||||
if (src.is_valid()) {
|
||||
dst.set(src.value());
|
||||
} else {
|
||||
dst.clear();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Issue #2129") {
|
||||
Nullable<float> nullable_value = Nullable<float>{123.4f};
|
||||
|
||||
JsonDocument doc;
|
||||
|
||||
doc["value"] = nullable_value;
|
||||
|
||||
REQUIRE(doc["value"].as<float>() == Approx(123.4f));
|
||||
}
|
@ -5,6 +5,8 @@
|
||||
#include <ArduinoJson.h>
|
||||
#include <catch.hpp>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
#if defined(__clang__)
|
||||
# define CONFLICTS_WITH_BUILTIN_OPERATOR
|
||||
#endif
|
||||
@ -111,7 +113,7 @@ TEST_CASE("unsigned char[]") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[key]);
|
||||
REQUIRE("world"_s == variant[key]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -122,7 +124,7 @@ TEST_CASE("unsigned char[]") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
const JsonVariant variant = doc.as<JsonVariant>();
|
||||
|
||||
REQUIRE(std::string("world") == variant[key]);
|
||||
REQUIRE("world"_s == variant[key]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -160,7 +162,7 @@ TEST_CASE("unsigned char[]") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj[key] = "world";
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("JsonObject::operator[] const") {
|
||||
@ -170,19 +172,10 @@ TEST_CASE("unsigned char[]") {
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
REQUIRE(std::string("world") == obj[key]);
|
||||
REQUIRE("world"_s == obj[key]);
|
||||
}
|
||||
#endif
|
||||
|
||||
SECTION("containsKey()") {
|
||||
unsigned char key[] = "hello";
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, "{\"hello\":\"world\"}");
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
REQUIRE(true == obj.containsKey(key));
|
||||
}
|
||||
|
||||
SECTION("remove()") {
|
||||
unsigned char key[] = "hello";
|
||||
|
||||
@ -203,7 +196,7 @@ TEST_CASE("unsigned char[]") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"] = value;
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
|
||||
SECTION("set()") {
|
||||
@ -213,7 +206,7 @@ TEST_CASE("unsigned char[]") {
|
||||
JsonObject obj = doc.to<JsonObject>();
|
||||
obj["hello"].set(value);
|
||||
|
||||
REQUIRE(std::string("world") == obj["hello"]);
|
||||
REQUIRE("world"_s == obj["hello"]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,7 +218,7 @@ TEST_CASE("unsigned char[]") {
|
||||
JsonArray arr = doc.to<JsonArray>();
|
||||
arr.add(value);
|
||||
|
||||
REQUIRE(std::string("world") == arr[0]);
|
||||
REQUIRE("world"_s == arr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +231,7 @@ TEST_CASE("unsigned char[]") {
|
||||
arr.add("hello");
|
||||
arr[0].set(value);
|
||||
|
||||
REQUIRE(std::string("world") == arr[0]);
|
||||
REQUIRE("world"_s == arr[0]);
|
||||
}
|
||||
|
||||
SECTION("operator=") {
|
||||
@ -249,7 +242,7 @@ TEST_CASE("unsigned char[]") {
|
||||
arr.add("hello");
|
||||
arr[0] = value;
|
||||
|
||||
REQUIRE(std::string("world") == arr[0]);
|
||||
REQUIRE("world"_s == arr[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ add_executable(MixedConfigurationTests
|
||||
enable_nan_1.cpp
|
||||
enable_progmem_1.cpp
|
||||
issue1707.cpp
|
||||
string_length_size_1.cpp
|
||||
string_length_size_2.cpp
|
||||
string_length_size_4.cpp
|
||||
use_double_0.cpp
|
||||
use_double_1.cpp
|
||||
use_long_long_0.cpp
|
||||
|
131
extras/tests/MixedConfiguration/string_length_size_1.cpp
Normal file
131
extras/tests/MixedConfiguration/string_length_size_1.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
#define ARDUINOJSON_STRING_LENGTH_SIZE 1
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 1") {
|
||||
JsonDocument doc;
|
||||
|
||||
SECTION("set(std::string)") {
|
||||
SECTION("returns true if len <= 255") {
|
||||
auto result = doc.set(std::string(255, '?'));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
SECTION("returns false if len >= 256") {
|
||||
auto result = doc.set(std::string(256, '?'));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set(MsgPackBinary)") {
|
||||
SECTION("returns true if size <= 253") {
|
||||
auto str = std::string(253, '?');
|
||||
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
SECTION("returns false if size >= 254") {
|
||||
auto str = std::string(254, '?');
|
||||
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set(MsgPackExtension)") {
|
||||
SECTION("returns true if size <= 252") {
|
||||
auto str = std::string(252, '?');
|
||||
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
SECTION("returns false if size >= 253") {
|
||||
auto str = std::string(253, '?');
|
||||
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
SECTION("returns Ok if string length <= 255") {
|
||||
auto input = "\"" + std::string(255, '?') + "\"";
|
||||
|
||||
auto err = deserializeJson(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if string length >= 256") {
|
||||
auto input = "\"" + std::string(256, '?') + "\"";
|
||||
|
||||
auto err = deserializeJson(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("deserializeMsgPack()") {
|
||||
SECTION("returns Ok if string length <= 255") {
|
||||
auto input = "\xd9\xff" + std::string(255, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if string length >= 256") {
|
||||
auto input = "\xda\x01\x00"_s + std::string(256, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
SECTION("returns Ok if binary size <= 253") {
|
||||
auto input = "\xc4\xfd" + std::string(253, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if binary size >= 254") {
|
||||
auto input = "\xc4\xfe" + std::string(254, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
SECTION("returns Ok if extension size <= 252") {
|
||||
auto input = "\xc7\xfc\x01" + std::string(252, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if binary size >= 253") {
|
||||
auto input = "\xc7\xfd\x01" + std::string(253, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
}
|
140
extras/tests/MixedConfiguration/string_length_size_2.cpp
Normal file
140
extras/tests/MixedConfiguration/string_length_size_2.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#define ARDUINOJSON_STRING_LENGTH_SIZE 2
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "Literals.hpp"
|
||||
|
||||
TEST_CASE("ARDUINOJSON_STRING_LENGTH_SIZE == 2") {
|
||||
JsonDocument doc;
|
||||
|
||||
SECTION("set(std::string)") {
|
||||
SECTION("returns true if len <= 65535") {
|
||||
auto result = doc.set(std::string(65535, '?'));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
SECTION("returns false if len >= 65536") {
|
||||
auto result = doc.set(std::string(65536, '?'));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set(MsgPackBinary)") {
|
||||
SECTION("returns true if size <= 65532") {
|
||||
auto str = std::string(65532, '?');
|
||||
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
SECTION("returns false if size >= 65533") {
|
||||
auto str = std::string(65533, '?');
|
||||
auto result = doc.set(MsgPackBinary(str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("set(MsgPackExtension)") {
|
||||
SECTION("returns true if size <= 65531") {
|
||||
auto str = std::string(65531, '?');
|
||||
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == true);
|
||||
REQUIRE(doc.overflowed() == false);
|
||||
}
|
||||
|
||||
SECTION("returns false if size >= 65532") {
|
||||
auto str = std::string(65532, '?');
|
||||
auto result = doc.set(MsgPackExtension(1, str.data(), str.size()));
|
||||
|
||||
REQUIRE(result == false);
|
||||
REQUIRE(doc.overflowed() == true);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("deserializeJson()") {
|
||||
SECTION("returns Ok if string length <= 65535") {
|
||||
auto input = "\"" + std::string(65535, '?') + "\"";
|
||||
|
||||
auto err = deserializeJson(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if string length >= 65536") {
|
||||
auto input = "\"" + std::string(65536, '?') + "\"";
|
||||
|
||||
auto err = deserializeJson(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("deserializeMsgPack()") {
|
||||
SECTION("returns Ok if string length <= 65535") {
|
||||
auto input = "\xda\xff\xff" + std::string(65535, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if string length >= 65536") {
|
||||
auto input = "\xdb\x00\x01\x00\x00"_s + std::string(65536, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
SECTION("returns Ok if binary size <= 65532") {
|
||||
auto input = "\xc5\xff\xfc" + std::string(65532, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if binary size >= 65534") {
|
||||
auto input = "\xc5\xff\xfd" + std::string(65534, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
// https://oss-fuzz.com/testcase?key=5354792971993088
|
||||
SECTION("doesn't overflow if binary size == 0xFFFF") {
|
||||
auto input = "\xc5\xff\xff"_s;
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
|
||||
SECTION("returns Ok if extension size <= 65531") {
|
||||
auto input = "\xc8\xff\xfb\x01" + std::string(65531, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::Ok);
|
||||
}
|
||||
|
||||
SECTION("returns NoMemory if extension size >= 65532") {
|
||||
auto input = "\xc8\xff\xfc\x01" + std::string(65532, '?');
|
||||
|
||||
auto err = deserializeMsgPack(doc, input);
|
||||
|
||||
REQUIRE(err == DeserializationError::NoMemory);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user