├── .all-contributorsrc
├── .editorconfig
├── .github
├── FUNDING.yml
└── workflows
│ ├── build_pull_request.yml
│ ├── build_push.yml
│ ├── msvc-analysis.yml
│ ├── sonarcloud.yml
│ └── test_cpp_versions.yml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── appveyor.yml
├── cmake
├── CMakeCompiler.cmake
├── CMakePlatforms.cmake
├── CMakeUtils.cmake
├── Toolchain-Android.cmake
└── Toolchain-iOS.cmake
├── external
└── README.md
├── includes
└── sjson
│ ├── error.h
│ ├── fwd.h
│ ├── impl
│ ├── bit_cast.impl.h
│ └── cstdlib.impl.h
│ ├── parser.h
│ ├── parser_error.h
│ ├── parser_state.h
│ ├── string_view.h
│ ├── version.h
│ └── writer.h
├── make.py
├── sonar-project.properties
├── tests
├── CMakeLists.txt
├── main_android
│ ├── CMakeLists.txt
│ ├── app
│ │ ├── build.gradle.in
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── cpp
│ │ │ ├── CMakeLists.txt
│ │ │ └── main.cpp
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── sjson
│ │ │ │ └── unit_tests
│ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ └── values
│ │ │ └── strings.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── main_emscripten
│ ├── CMakeLists.txt
│ └── main.cpp
├── main_generic
│ ├── CMakeLists.txt
│ └── main.cpp
├── main_ios
│ ├── CMakeLists.txt
│ └── main.cpp
├── sources
│ ├── catch2.impl.h
│ ├── test_header_fwd.cpp
│ ├── test_parser.cpp
│ ├── test_string_view.cpp
│ └── test_writer.cpp
└── validate_includes
│ ├── CMakeLists.txt
│ ├── dummy.cpp
│ └── single_include.cpp.in
└── tools
├── appveyor_ci.bat
├── release_scripts
└── test_everything.py
├── setup_linux_compiler.sh
├── setup_osx_compiler.sh
└── vs_visualizers
└── sjson-cpp.natvis
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "files": [
3 | "README.md"
4 | ],
5 | "imageSize": 100,
6 | "commit": false,
7 | "contributors": [
8 | {
9 | "login": "CodyDWJones",
10 | "name": "CodyDWJones",
11 | "avatar_url": "https://avatars.githubusercontent.com/u/28773740?v=4",
12 | "profile": "https://github.com/CodyDWJones",
13 | "contributions": [
14 | "code",
15 | "maintenance"
16 | ]
17 | },
18 | {
19 | "login": "janisozaur",
20 | "name": "Michał Janiszewski",
21 | "avatar_url": "https://avatars.githubusercontent.com/u/550290?v=4",
22 | "profile": "https://github.com/janisozaur",
23 | "contributions": [
24 | "code",
25 | "maintenance"
26 | ]
27 | },
28 | {
29 | "login": "tirpidz",
30 | "name": "Martin Turcotte",
31 | "avatar_url": "https://avatars.githubusercontent.com/u/9991876?v=4",
32 | "profile": "https://github.com/tirpidz",
33 | "contributions": [
34 | "maintenance"
35 | ]
36 | },
37 | {
38 | "login": "Meradrin",
39 | "name": "Meradrin",
40 | "avatar_url": "https://avatars.githubusercontent.com/u/7066278?v=4",
41 | "profile": "https://github.com/Meradrin",
42 | "contributions": [
43 | "bug"
44 | ]
45 | }
46 | ],
47 | "contributorsPerLine": 7,
48 | "projectName": "sjson-cpp",
49 | "projectOwner": "nfrechette",
50 | "repoType": "github",
51 | "repoHost": "https://github.com",
52 | "skipCi": true
53 | }
54 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | # Matches multiple files with brace expansion notation
8 | [*.{cpp,h,py,cmake,txt,java}]
9 | charset = utf-8
10 | indent_style = tab
11 | indent_size = 4
12 | trim_trailing_whitespace = true
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
17 | [*.{gradle,gradle.in}]
18 | indent_style = space
19 | indent_size = 4
20 | trim_trailing_whitespace = true
21 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | #github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | #patreon: # Replace with a single Patreon username
5 | #open_collective: # Replace with a single Open Collective username
6 | #ko_fi: # Replace with a single Ko-fi username
7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | #liberapay: # Replace with a single Liberapay username
10 | #issuehunt: # Replace with a single IssueHunt username
11 | #otechie: # Replace with a single Otechie username
12 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
14 | github: [nfrechette]
15 |
--------------------------------------------------------------------------------
/.github/workflows/build_pull_request.yml:
--------------------------------------------------------------------------------
1 | name: build pull request
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - '**'
7 | paths-ignore:
8 | - '**/*.md'
9 |
10 | jobs:
11 | linux-xenial:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | compiler: [clang4]
16 | steps:
17 | - name: Git checkout
18 | uses: actions/checkout@v4
19 | with:
20 | submodules: 'recursive'
21 | - name: Building (debug-x86)
22 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
23 | with:
24 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -build'
25 | - name: Running unit tests (debug-x86)
26 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
27 | with:
28 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -unit_test'
29 | - name: Clean
30 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
31 | with:
32 | args: 'python3 make.py -clean_only'
33 | - name: Building (debug-x64)
34 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
35 | with:
36 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -build'
37 | - name: Running unit tests (debug-x64)
38 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
39 | with:
40 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -unit_test'
41 | - name: Clean
42 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
43 | with:
44 | args: 'python3 make.py -clean_only'
45 | - name: Building (release-x86)
46 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
47 | with:
48 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -build'
49 | - name: Running unit tests (release-x86)
50 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
51 | with:
52 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -unit_test'
53 | - name: Clean
54 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
55 | with:
56 | args: 'python3 make.py -clean_only'
57 | - name: Building (release-x64)
58 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
59 | with:
60 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -build'
61 | - name: Running unit tests (release-x64)
62 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-xenial:v1
63 | with:
64 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -unit_test'
65 |
66 | linux-bionic:
67 | runs-on: ubuntu-latest
68 | strategy:
69 | matrix:
70 | compiler: [gcc5, gcc6, gcc7, gcc8, clang5, clang6, clang7, clang8, clang9, clang10]
71 | steps:
72 | - name: Git checkout
73 | uses: actions/checkout@v4
74 | with:
75 | submodules: 'recursive'
76 | - name: Building (debug-x86)
77 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
78 | with:
79 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -build'
80 | - name: Running unit tests (debug-x86)
81 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
82 | with:
83 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -unit_test'
84 | - name: Clean
85 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
86 | with:
87 | args: 'python3 make.py -clean_only'
88 | - name: Building (debug-x64)
89 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
90 | with:
91 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -build'
92 | - name: Running unit tests (debug-x64)
93 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
94 | with:
95 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -unit_test'
96 | - name: Clean
97 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
98 | with:
99 | args: 'python3 make.py -clean_only'
100 | - name: Building (release-x86)
101 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
102 | with:
103 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -build'
104 | - name: Running unit tests (release-x86)
105 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
106 | with:
107 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -unit_test'
108 | - name: Clean
109 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
110 | with:
111 | args: 'python3 make.py -clean_only'
112 | - name: Building (release-x64)
113 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
114 | with:
115 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -build'
116 | - name: Running unit tests (release-x64)
117 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-bionic:v1
118 | with:
119 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -unit_test'
120 |
121 | linux-focal:
122 | runs-on: ubuntu-latest
123 | strategy:
124 | matrix:
125 | compiler: [gcc9, gcc10, gcc11, clang11, clang12, clang13, clang14]
126 | steps:
127 | - name: Git checkout
128 | uses: actions/checkout@v4
129 | with:
130 | submodules: 'recursive'
131 | - name: Building (debug-x86)
132 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
133 | with:
134 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -build'
135 | - name: Running unit tests (debug-x86)
136 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
137 | with:
138 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -unit_test'
139 | - name: Clean
140 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
141 | with:
142 | args: 'python3 make.py -clean_only'
143 | - name: Building (debug-x64)
144 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
145 | with:
146 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -build'
147 | - name: Running unit tests (debug-x64)
148 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
149 | with:
150 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -unit_test'
151 | - name: Clean
152 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
153 | with:
154 | args: 'python3 make.py -clean_only'
155 | - name: Building (release-x86)
156 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
157 | with:
158 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -build'
159 | - name: Running unit tests (release-x86)
160 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
161 | with:
162 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -unit_test'
163 | - name: Clean
164 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
165 | with:
166 | args: 'python3 make.py -clean_only'
167 | - name: Building (release-x64)
168 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
169 | with:
170 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -build'
171 | - name: Running unit tests (release-x64)
172 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-focal:v1
173 | with:
174 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -unit_test'
175 |
176 | linux-lunar:
177 | runs-on: ubuntu-latest
178 | strategy:
179 | matrix:
180 | compiler: [gcc12, gcc13, clang15, clang16, clang17, clang18]
181 | steps:
182 | - name: Git checkout
183 | uses: actions/checkout@v4
184 | with:
185 | submodules: 'recursive'
186 | - name: Building (debug-x86)
187 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
188 | with:
189 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -build'
190 | - name: Running unit tests (debug-x86)
191 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
192 | with:
193 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -unit_test'
194 | - name: Clean
195 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
196 | with:
197 | args: 'python3 make.py -clean_only'
198 | - name: Building (debug-x64)
199 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
200 | with:
201 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -build'
202 | - name: Running unit tests (debug-x64)
203 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
204 | with:
205 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -unit_test'
206 | - name: Clean
207 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
208 | with:
209 | args: 'python3 make.py -clean_only'
210 | - name: Building (release-x86)
211 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
212 | with:
213 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -build'
214 | - name: Running unit tests (release-x86)
215 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
216 | with:
217 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -unit_test'
218 | - name: Clean
219 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
220 | with:
221 | args: 'python3 make.py -clean_only'
222 | - name: Building (release-x64)
223 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
224 | with:
225 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -build'
226 | - name: Running unit tests (release-x64)
227 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
228 | with:
229 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -unit_test'
230 |
231 | osx-12:
232 | runs-on: macos-12
233 | strategy:
234 | matrix:
235 | compiler: [xcode13]
236 | steps:
237 | - name: Git checkout
238 | uses: actions/checkout@v4
239 | with:
240 | submodules: 'recursive'
241 | - name: Setup ${{ matrix.compiler }} compiler
242 | run: ./tools/setup_osx_compiler.sh ${{ matrix.compiler }}
243 | - name: Building (debug-x64)
244 | run: python3 make.py -ci -compiler osx -config Debug -cpu x64 -build
245 | - name: Running unit tests (debug-x64)
246 | run: python3 make.py -ci -compiler osx -config Debug -cpu x64 -unit_test
247 | - name: Clean
248 | run: python3 make.py -clean_only
249 | - name: Building (release-x64)
250 | run: python3 make.py -ci -compiler osx -config Release -cpu x64 -build
251 | - name: Running unit tests (release-x64)
252 | run: python3 make.py -ci -compiler osx -config Release -cpu x64 -unit_test
253 | - name: Clean
254 | run: python3 make.py -clean_only
255 | - name: Building for iOS (debug-arm64)
256 | run: python3 make.py -ci -compiler ios -config Debug -build
257 | - name: Clean
258 | run: python3 make.py -clean_only
259 | - name: Building for iOS (release-arm64)
260 | run: python3 make.py -ci -compiler ios -config Release -build
261 |
262 | osx-14:
263 | runs-on: macos-14
264 | strategy:
265 | matrix:
266 | compiler: [xcode14, xcode15]
267 | steps:
268 | - name: Git checkout
269 | uses: actions/checkout@v4
270 | with:
271 | submodules: 'recursive'
272 | - name: Setup ${{ matrix.compiler }} compiler
273 | run: ./tools/setup_osx_compiler.sh ${{ matrix.compiler }}
274 | - name: Building (debug-arm64)
275 | run: python3 make.py -ci -compiler osx -config Debug -build
276 | - name: Running unit tests (debug-arm64)
277 | run: python3 make.py -ci -compiler osx -config Debug -unit_test
278 | - name: Clean
279 | run: python3 make.py -clean_only
280 | - name: Building (release-arm64)
281 | run: python3 make.py -ci -compiler osx -config Release -build
282 | - name: Running unit tests (release-arm64)
283 | run: python3 make.py -ci -compiler osx -config Release -unit_test
284 | - name: Clean
285 | run: python3 make.py -clean_only
286 | - name: Building for iOS (debug-arm64)
287 | run: python3 make.py -ci -compiler ios -config Debug -build
288 | - name: Clean
289 | run: python3 make.py -clean_only
290 | - name: Building for iOS (release-arm64)
291 | run: python3 make.py -ci -compiler ios -config Release -build
292 |
293 | emscripten:
294 | runs-on: ubuntu-latest
295 | steps:
296 | - name: Git checkout
297 | uses: actions/checkout@v4
298 | with:
299 | submodules: 'recursive'
300 | - name: Building (debug)
301 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
302 | with:
303 | args: 'python3 make.py -ci -compiler emscripten -config debug -build'
304 | - name: Running unit tests (debug)
305 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
306 | with:
307 | args: 'python3 make.py -ci -compiler emscripten -config debug -unit_test'
308 | - name: Clean
309 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
310 | with:
311 | args: 'python3 make.py -clean_only'
312 | - name: Building (release)
313 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
314 | with:
315 | args: 'python3 make.py -ci -compiler emscripten -config release -build'
316 | - name: Running unit tests (release)
317 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
318 | with:
319 | args: 'python3 make.py -ci -compiler emscripten -config release -unit_test'
320 |
321 | vs2019:
322 | runs-on: windows-2019
323 | steps:
324 | - name: Git checkout
325 | uses: actions/checkout@v4
326 | with:
327 | submodules: 'recursive'
328 | - name: Building (debug-x64)
329 | run: python3 make.py -ci -compiler vs2019 -config Debug -cpu x64 -build
330 | - name: Running unit tests (debug-x64)
331 | run: python3 make.py -ci -compiler vs2019 -config Debug -cpu x64 -unit_test
332 | - name: Clean
333 | run: python3 make.py -clean_only
334 | - name: Building (release-x64)
335 | run: python3 make.py -ci -compiler vs2019 -config Release -cpu x64 -build
336 | - name: Running unit tests (release-x64)
337 | run: python3 make.py -ci -compiler vs2019 -config Release -cpu x64 -unit_test
338 | - name: Clean
339 | run: python3 make.py -clean_only
340 | - name: Building (debug-arm64)
341 | run: python3 make.py -ci -compiler vs2019 -config Debug -cpu arm64 -build
342 | - name: Clean
343 | run: python3 make.py -clean_only
344 | - name: Building (release-arm64)
345 | run: python3 make.py -ci -compiler vs2019 -config Release -cpu arm64 -build
346 | - name: Clean
347 | run: python3 make.py -clean_only
348 | - name: Building (debug-x64) with Clang
349 | run: python3 make.py -ci -compiler vs2019-clang -config Debug -cpu x64 -build
350 | - name: Running unit tests (debug-x64) with Clang
351 | run: python3 make.py -ci -compiler vs2019-clang -config Debug -cpu x64 -unit_test
352 | - name: Clean
353 | run: python3 make.py -clean_only
354 | - name: Building (release-x64) with Clang
355 | run: python3 make.py -ci -compiler vs2019-clang -config Release -cpu x64 -build
356 | - name: Running unit tests (release-x64) with Clang
357 | run: python3 make.py -ci -compiler vs2019-clang -config Release -cpu x64 -unit_test
358 |
359 | vs2022:
360 | runs-on: windows-2022
361 | steps:
362 | - name: Git checkout
363 | uses: actions/checkout@v4
364 | with:
365 | submodules: 'recursive'
366 | - name: Building (debug-x64)
367 | run: python3 make.py -ci -compiler vs2022 -config Debug -cpu x64 -build
368 | - name: Running unit tests (debug-x64)
369 | run: python3 make.py -ci -compiler vs2022 -config Debug -cpu x64 -unit_test
370 | - name: Clean
371 | run: python3 make.py -clean_only
372 | - name: Building (release-x64)
373 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x64 -build
374 | - name: Running unit tests (release-x64)
375 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x64 -unit_test
376 | - name: Clean
377 | run: python3 make.py -clean_only
378 | - name: Building (debug-arm64)
379 | run: python3 make.py -ci -compiler vs2022 -config Debug -cpu arm64 -build
380 | - name: Clean
381 | run: python3 make.py -clean_only
382 | - name: Building (release-arm64)
383 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu arm64 -build
384 | - name: Clean
385 | run: python3 make.py -clean_only
386 | - name: Building (debug-x64) with Clang
387 | run: python3 make.py -ci -compiler vs2022-clang -config Debug -cpu x64 -build
388 | - name: Running unit tests (debug-x64) with Clang
389 | run: python3 make.py -ci -compiler vs2022-clang -config Debug -cpu x64 -unit_test
390 | - name: Clean
391 | run: python3 make.py -clean_only
392 | - name: Building (release-x64) with Clang
393 | run: python3 make.py -ci -compiler vs2022-clang -config Release -cpu x64 -build
394 | - name: Running unit tests (release-x64) with Clang
395 | run: python3 make.py -ci -compiler vs2022-clang -config Release -cpu x64 -unit_test
396 |
--------------------------------------------------------------------------------
/.github/workflows/build_push.yml:
--------------------------------------------------------------------------------
1 | name: build push
2 |
3 | on:
4 | push:
5 | branches:
6 | - '**'
7 | paths-ignore:
8 | - '**/*.md'
9 |
10 | jobs:
11 | linux:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | compiler: [gcc13, clang18]
16 | steps:
17 | - name: Git checkout
18 | uses: actions/checkout@v4
19 | with:
20 | submodules: 'recursive'
21 | - name: Building (debug-x86)
22 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
23 | with:
24 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -build'
25 | - name: Running unit tests (debug-x86)
26 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
27 | with:
28 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x86 -unit_test'
29 | - name: Clean
30 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
31 | with:
32 | args: 'python3 make.py -clean_only'
33 | - name: Building (debug-x64)
34 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
35 | with:
36 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -build'
37 | - name: Running unit tests (debug-x64)
38 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
39 | with:
40 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Debug -cpu x64 -unit_test'
41 | - name: Clean
42 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
43 | with:
44 | args: 'python3 make.py -clean_only'
45 | - name: Building (release-x86)
46 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
47 | with:
48 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -build'
49 | - name: Running unit tests (release-x86)
50 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
51 | with:
52 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -unit_test'
53 | - name: Clean
54 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
55 | with:
56 | args: 'python3 make.py -clean_only'
57 | - name: Building (release-x64)
58 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
59 | with:
60 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -build'
61 | - name: Running unit tests (release-x64)
62 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
63 | with:
64 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -unit_test'
65 |
66 | osx-14:
67 | runs-on: macos-14
68 | strategy:
69 | matrix:
70 | compiler: [xcode15]
71 | steps:
72 | - name: Git checkout
73 | uses: actions/checkout@v4
74 | with:
75 | submodules: 'recursive'
76 | - name: Setup ${{ matrix.compiler }} compiler
77 | run: ./tools/setup_osx_compiler.sh ${{ matrix.compiler }}
78 | - name: Building (debug-arm64)
79 | run: python3 make.py -ci -compiler osx -config Debug -build
80 | - name: Running unit tests (debug-arm64)
81 | run: python3 make.py -ci -compiler osx -config Debug -unit_test
82 | - name: Clean
83 | run: python3 make.py -clean_only
84 | - name: Building (release-arm64)
85 | run: python3 make.py -ci -compiler osx -config Release -build
86 | - name: Running unit tests (release-arm64)
87 | run: python3 make.py -ci -compiler osx -config Release -unit_test
88 | - name: Clean
89 | run: python3 make.py -clean_only
90 | - name: Building for iOS (debug-arm64)
91 | run: python3 make.py -ci -compiler ios -config Debug -build
92 | - name: Clean
93 | run: python3 make.py -clean_only
94 | - name: Building for iOS (release-arm64)
95 | run: python3 make.py -ci -compiler ios -config Release -build
96 |
97 | emscripten:
98 | runs-on: ubuntu-latest
99 | steps:
100 | - name: Git checkout
101 | uses: actions/checkout@v4
102 | with:
103 | submodules: 'recursive'
104 | - name: Building (debug)
105 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
106 | with:
107 | args: 'python3 make.py -ci -compiler emscripten -config debug -build'
108 | - name: Running unit tests (debug)
109 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
110 | with:
111 | args: 'python3 make.py -ci -compiler emscripten -config debug -unit_test'
112 | - name: Clean
113 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
114 | with:
115 | args: 'python3 make.py -clean_only'
116 | - name: Building (release)
117 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
118 | with:
119 | args: 'python3 make.py -ci -compiler emscripten -config release -build'
120 | - name: Running unit tests (release)
121 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-emscripten:v1
122 | with:
123 | args: 'python3 make.py -ci -compiler emscripten -config release -unit_test'
124 |
125 | vs2022:
126 | runs-on: windows-2022
127 | steps:
128 | - name: Git checkout
129 | uses: actions/checkout@v4
130 | with:
131 | submodules: 'recursive'
132 | - name: Building (debug-x64)
133 | run: python3 make.py -ci -compiler vs2022 -config Debug -cpu x64 -build
134 | - name: Running unit tests (debug-x64)
135 | run: python3 make.py -ci -compiler vs2022 -config Debug -cpu x64 -unit_test
136 | - name: Clean
137 | run: python3 make.py -clean_only
138 | - name: Building (release-x64)
139 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x64 -build
140 | - name: Running unit tests (release-x64)
141 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x64 -unit_test
142 | - name: Clean
143 | run: python3 make.py -clean_only
144 | - name: Building (debug-arm64)
145 | run: python3 make.py -ci -compiler vs2022 -config Debug -cpu arm64 -build
146 | - name: Clean
147 | run: python3 make.py -clean_only
148 | - name: Building (release-arm64)
149 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu arm64 -build
150 | - name: Clean
151 | run: python3 make.py -clean_only
152 | - name: Building (debug-x64) with Clang
153 | run: python3 make.py -ci -compiler vs2022-clang -config Debug -cpu x64 -build
154 | - name: Running unit tests (debug-x64) with Clang
155 | run: python3 make.py -ci -compiler vs2022-clang -config Debug -cpu x64 -unit_test
156 | - name: Clean
157 | run: python3 make.py -clean_only
158 | - name: Building (release-x64) with Clang
159 | run: python3 make.py -ci -compiler vs2022-clang -config Release -cpu x64 -build
160 | - name: Running unit tests (release-x64) with Clang
161 | run: python3 make.py -ci -compiler vs2022-clang -config Release -cpu x64 -unit_test
162 |
--------------------------------------------------------------------------------
/.github/workflows/msvc-analysis.yml:
--------------------------------------------------------------------------------
1 | name: msvc analysis
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - '**'
7 | paths-ignore:
8 | - '**/*.md'
9 |
10 | jobs:
11 | # We use the presence of the sonar token to detect if the PR comes from a fork
12 | condition-check:
13 | runs-on: ubuntu-latest
14 | outputs:
15 | ok: ${{ steps.check-secrets.outputs.ok }}
16 | steps:
17 | - name: Secret guard
18 | id: check-secrets
19 | run: |
20 | if [ ! -z "${{ secrets.SONAR_TOKEN }}" ]; then
21 | echo "ok=true" >> $GITHUB_OUTPUT
22 | fi
23 | vs2022:
24 | needs:
25 | - condition-check
26 | runs-on: windows-2022
27 | steps:
28 | - name: Git checkout
29 | uses: actions/checkout@v3
30 | with:
31 | submodules: 'recursive'
32 | - name: Generate solution (release-x64)
33 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x64
34 | - name: Run MSVC Code Analysis
35 | uses: microsoft/msvc-code-analysis-action@v0.1.1
36 | id: run-analysis
37 | with:
38 | cmakeBuildDirectory: ${{ github.workspace }}/build
39 | buildConfiguration: Release
40 | ruleset: NativeRecommendedRules.ruleset
41 | ignoredPaths: ${{ github.workspace }}/external
42 | - name: Upload SARIF to GitHub
43 | # Can only upload SARIF if we don't come from a fork
44 | if: ${{ needs.condition-check.outputs.ok == 'true' }}
45 | uses: github/codeql-action/upload-sarif@v2
46 | with:
47 | sarif_file: ${{ steps.run-analysis.outputs.sarif }}
48 | - name: Upload SARIF as an Artifact
49 | uses: actions/upload-artifact@v2
50 | with:
51 | name: sarif-file
52 | path: ${{ steps.run-analysis.outputs.sarif }}
53 |
--------------------------------------------------------------------------------
/.github/workflows/sonarcloud.yml:
--------------------------------------------------------------------------------
1 | name: sonarcloud
2 |
3 | on:
4 | push:
5 | branches:
6 | - '**'
7 | paths-ignore:
8 | - '**/*.md'
9 | pull_request:
10 | branches:
11 | - '**'
12 | paths-ignore:
13 | - '**/*.md'
14 |
15 | jobs:
16 | condition-check:
17 | runs-on: ubuntu-latest
18 | outputs:
19 | ok: ${{ steps.check-secrets.outputs.ok }}
20 | steps:
21 | - name: Secret guard
22 | id: check-secrets
23 | run: |
24 | if [ ! -z "${{ secrets.SONAR_TOKEN }}" ]; then
25 | echo "ok=true" >> $GITHUB_OUTPUT
26 | fi
27 | sonarcloud:
28 | needs:
29 | - condition-check
30 | if: ${{ needs.condition-check.outputs.ok == 'true' }}
31 | runs-on: ubuntu-latest
32 | steps:
33 | - name: Git checkout
34 | uses: actions/checkout@v4
35 | with:
36 | submodules: 'recursive'
37 | - name: Build with wrapper
38 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-sonarcloud:v3
39 | with:
40 | args: '/build-wrapper-linux-x86/build-wrapper-linux-x86-64 --out-dir bw_output python3 make.py -compiler clang15 -config Release -cpu x64 -build'
41 | - name: Run Sonar Scanner and upload to Sonarcloud
42 | env:
43 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
45 | SONAR_HOST_URL: https://sonarcloud.io
46 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-linux-sonarcloud:v3
47 | with:
48 | args: '/sonar-scanner-5.0.1.3006-linux/bin/sonar-scanner'
49 |
--------------------------------------------------------------------------------
/.github/workflows/test_cpp_versions.yml:
--------------------------------------------------------------------------------
1 | name: test cpp versions
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - '**'
7 | paths-ignore:
8 | - '**/*.md'
9 |
10 | jobs:
11 | linux:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | compiler: [gcc13, clang18]
16 | cpp_version: [14, 17, 20]
17 | steps:
18 | - name: Git checkout
19 | uses: actions/checkout@v3
20 | with:
21 | submodules: 'recursive'
22 | - name: Building (release-x86)
23 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
24 | with:
25 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x86 -cpp_version ${{ matrix.cpp_version }} -build'
26 | - name: Clean
27 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
28 | with:
29 | args: 'python3 make.py -clean_only'
30 | - name: Building (release-x64)
31 | uses: docker://ghcr.io/nfrechette/toolchain-amd64-lunar:v2
32 | with:
33 | args: 'python3 make.py -ci -compiler ${{ matrix.compiler }} -config Release -cpu x64 -cpp_version ${{ matrix.cpp_version }} -build'
34 |
35 | vs2022:
36 | runs-on: windows-2022
37 | strategy:
38 | matrix:
39 | cpp_version: [14, 17, 20]
40 | steps:
41 | - name: Git checkout
42 | uses: actions/checkout@v3
43 | with:
44 | submodules: 'recursive'
45 | - name: Building (release-x86)
46 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x86 -cpp_version ${{ matrix.cpp_version }} -build
47 | - name: Clean
48 | run: python3 make.py -clean_only
49 | - name: Building (release-x64)
50 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu x64 -cpp_version ${{ matrix.cpp_version }} -build
51 | - name: Clean
52 | run: python3 make.py -clean_only
53 | - name: Building (release-arm64)
54 | run: python3 make.py -ci -compiler vs2022 -config Release -cpu arm64 -cpp_version ${{ matrix.cpp_version }} -build
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Temporary data rules
2 | build/
3 | *.suo
4 | **/__pycache__/
5 | .vscode/
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "external/catch2"]
2 | path = external/catch2
3 | url = https://github.com/catchorg/Catch2
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Significant changes per release
2 |
3 | ## 0.9.0
4 |
5 | * Added support for Clang 12, 13, 14, and 15
6 | * Added support for GCC 11, 12, and 13
7 | * Added support for XCode 14
8 | * Added support for VS2022
9 | * Added support for MSYS2
10 | * Added support for C++14, C++17, and C++20
11 | * CI now uses docker where possible
12 | * Lots of static analysis fixes and improvements
13 | * Misc minor improvements
14 |
15 | ## 0.8.3
16 |
17 | * Force macro expansion in version namespace identifier
18 |
19 | ## 0.8.2
20 |
21 | * Add versioned namespace to allow multiple versions to coexist within a binary
22 | * Add OS X/Linux ARM development support
23 | * Other minor changes
24 |
25 | ## 0.8.1
26 |
27 | * Minor static analysis fixes
28 |
29 | ## 0.8.0
30 |
31 | * Added support for clang 8, 9, and 10
32 | * Added support for GCC 10
33 | * Added support for clang with VS 2019
34 | * Added support for emscripten
35 | * Converted android to use gradle instead of NVIDIA CodeWorks
36 | * Updated Catch2 to 2.11.0
37 | * Migrated from Travis to GitHub Actions
38 | * Cleanup and minor misc changes
39 |
40 | ## 0.7.0
41 |
42 | * Added support for VS 2019, GCC 9, clang 7, and Xcode 11
43 | * Added custom support for NaN/Inf handling
44 | * Cleanup and minor misc changes
45 |
46 | ## 0.6.0
47 |
48 | * Added support for Windows ARM64, GCC 8, clang 6, and Xcode 10
49 | * Integrated SonarCloud
50 | * Cleanup and minor changes & fixes
51 |
52 | ## 0.5.0
53 |
54 | * Cleaned up error handling
55 | * Enabled as many warnings as possible
56 | * Other minor misc changes
57 |
58 | ## 0.4.0
59 |
60 | * Added iOS support
61 | * Other misc additions
62 |
63 | ## 0.3.0
64 |
65 | * Added Android support through NVIDIA CodeWorks
66 | * Added cmake utilities
67 |
68 | ## 0.2.0
69 |
70 | * New SJSON file writer added
71 | * Added unit tests
72 | * Added contributing guidelines, setup instructions, code of conduct
73 | * Added CI builds with AppVeyor and Travis
74 | * Added support for Linux and OS X
75 | * Various other fixes and additions
76 |
77 | ## 0.1.0
78 |
79 | Initial release!
80 |
81 | * Reads SJSON files in ANSI or UTF-8
82 | * Nothing fancy, works as advertised
83 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 | project(sjson-cpp CXX)
3 |
4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
5 |
6 | include(CMakeUtils)
7 | include(CMakeCompiler)
8 | include(CMakePlatforms)
9 |
10 | set(CPU_INSTRUCTION_SET false CACHE STRING "CPU instruction set")
11 |
12 | if(CMAKE_CONFIGURATION_TYPES)
13 | set(CMAKE_CONFIGURATION_TYPES Debug Release)
14 | set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "Reset the configurations to what we need" FORCE)
15 | endif()
16 |
17 | # Grab all of our include files
18 | file(GLOB_RECURSE SJSON_CPP_INCLUDE_FILES LIST_DIRECTORIES false
19 | ${PROJECT_SOURCE_DIR}/includes/*.h
20 | ${PROJECT_SOURCE_DIR}/*.md
21 | ${PROJECT_SOURCE_DIR}/cmake/*.cmake
22 | ${PROJECT_SOURCE_DIR}/tools/release_scripts/*.py
23 | ${PROJECT_SOURCE_DIR}/tools/vs_visualizers/*.natvis
24 | )
25 |
26 | create_source_groups("${SJSON_CPP_INCLUDE_FILES}" ${PROJECT_SOURCE_DIR})
27 |
28 | file(GLOB SJSON_CPP_ROOT_FILES LIST_DIRECTORIES false
29 | ${PROJECT_SOURCE_DIR}/*.md
30 | ${PROJECT_SOURCE_DIR}/*.py)
31 |
32 | # Create a dummy target so they show up in the IDE
33 | add_custom_target(${PROJECT_NAME} SOURCES ${SJSON_CPP_INCLUDE_FILES} ${SJSON_CPP_ROOT_FILES})
34 |
35 | # Enable CTest
36 | enable_testing()
37 |
38 | # Add other projects
39 | add_subdirectory("${PROJECT_SOURCE_DIR}/tests")
40 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at zeno490@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | Thank you for your interest in the sjson-cpp! All contributions that follow our guidelines below and abide by our [code of conduct](CODE_OF_CONDUCT.md) are welcome.
4 |
5 | In this document you will find relevant reading material, what contributions we are looking for, and what we are *not* looking for.
6 |
7 | Project contact email: zeno490@gmail.com
8 |
9 | # Getting set up
10 |
11 | See the [readme](README.md) file for details on how to generate project solutions, build, and run the unit tests. Every pull request should run with continuous integration on every platform we support and the unit tests will also execute as well.
12 |
13 | The project uses [GitHub issues](https://github.com/nfrechette/sjson-cpp/issues) to track bugs and feature requests.
14 |
15 | Whether you create an issue or a pull request, I will do my best to comment or reply within 48 hours.
16 |
17 | # Contributions we are looking for
18 |
19 | Several issues already have a [help wanted](https://github.com/nfrechette/sjson-cpp/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) label. Those tasks should be either reasonably simple or tasks that I do not think I will get the chance to get to very soon.
20 |
21 | Feature requests are welcome providing that they fit within the project scope. For smaller features, you are welcome to create an issue with as much relevant information as you can. If it makes sense, I will prioritize it or add it to the backlog, and if I feel it is beyond the scope of the project, I will tell you why and close the issue. For larger topics, the best way to move forward is to reach out by email.
22 |
23 | # Contributions we are *not* looking for
24 |
25 | A lot of older compilers do not properly support C++11 and there is no plan to support them. This also applies to platforms that are either not mainstream or that we cannot easily test with continuous integration. If you would like to support such an exotic environment, reach out by email first so we can discuss this.
26 |
27 | If you aren't sure, don't be afraid to reach out by email!
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://cla-assistant.io/nfrechette/sjson-cpp)
2 | [](#contributors-)
3 | [](https://ci.appveyor.com/project/nfrechette/sjson-cpp)
4 | [](https://github.com/nfrechette/sjson-cpp/actions)
5 | [](https://sonarcloud.io/dashboard?id=nfrechette_sjson-cpp)
6 | [](https://github.com/nfrechette/sjson-cpp/releases)
7 | [](https://raw.githubusercontent.com/nfrechette/sjson-cpp/master/LICENSE)
8 |
9 | # sjson-cpp
10 |
11 | `sjson-cpp` is a C++ library to read and write [Simplified JSON](http://help.autodesk.com/view/Stingray/ENU/?guid=__stingray_help_managing_content_sjson_html) files.
12 | It aims to be minimal, fast, and get out of the way of the programmer.
13 |
14 | By design, the library does no memory allocations. This is in contrast to the [nflibs C parser](https://github.com/niklasfrykholm/nflibs).
15 |
16 | Everything is **100% C++11** header based for easy and trivial integration.
17 |
18 | This parser is intended to accept only pure SJSON, and it will fail if given a JSON file, unlike the [Autodesk JS Stingray parser](https://github.com/Autodesk/sjson).
19 |
20 | ## The SJSON format
21 |
22 | The data format is described [here](http://help.autodesk.com/view/Stingray/ENU/?guid=__stingray_help_managing_content_sjson_html) in the Stingray documentation.
23 |
24 | TODO: Add a reference sjson file showing the format as a form of loose specification
25 |
26 | ## Unicode support
27 |
28 | UTF-8 support is as follow:
29 |
30 | * String values return a raw `StringView` into the SJSON buffer. It is the responsability of the caller to interpret it as ANSI or UTF-8.
31 | * String values properly support escaped unicode sequences in that they are returned raw in the `StringView`.
32 | * Keys do not support UTF-8, they must be ANSI.
33 | * The BOM is properly skipped if present
34 |
35 | Unicode formats other than UTF-8 aren't supported.
36 |
37 | ## Supported platforms
38 |
39 | * Windows VS2015 x86 and x64
40 | * Windows (VS2017 to VS2022) x86, x64, and ARM64
41 | * Windows (VS2017 to VS2022) with clang x86 and x64
42 | * Linux (gcc 5 to 13) x86 and x64
43 | * Linux (clang 4 to 15) x86 and x64
44 | * OS X (XCode 12.5, 13.2, 14.2) x64 and ARM64
45 | * Android (NDK 21) ARMv7-A and ARM64
46 | * iOS (Xcode 10.3, 11.7, 12.5, 13.2, 14.2) ARM64
47 | * Emscripten (1.39.11) WASM
48 | * MSYS2 x64
49 |
50 | The above supported platform list is only what is tested every release but if it compiles, it should run just fine.
51 |
52 | ## External dependencies
53 |
54 | There are none! You don't need anything else to get started: everything is self contained.
55 | See [here](./external) for details.
56 |
57 | ## Getting up and running
58 |
59 | This library is **100%** headers as such you just need to include them in your own project to start using it. However, if you wish to run the unit tests you will need a few things, see below.
60 |
61 | ### Windows, Linux, and OS X for x86 and x64
62 |
63 | 1. Install *CMake 3.2* or higher (*3.14* for Visual Studio 2019, or *3.10* on OS X with *Xcode 10*), *Python 2.7 or 3*, and the proper compiler for your platform.
64 | 2. Execute `git submodule update --init` to get the files of external submodules (e.g. Catch2).
65 | 3. Generate the IDE solution with: `python make.py`
66 | The solution is generated under `./build`
67 | 4. Build the IDE solution with: `python make.py -build`
68 | 5. Run the unit tests with: `python make.py -unit_test`
69 |
70 | ### Windows ARM64
71 |
72 | For *Windows on ARM64*, the steps are identical to *x86 and x64* but you will need *CMake 3.13 or higher* and you must provide the architecture on the command line: `python make.py -compiler vs2017 -cpu arm64`
73 |
74 | ### Android
75 |
76 | For *Android*, the steps are identical to *Windows, Linux, and OS X* but you also need to install *Android NDK 21* (or higher). The build uses `gradle` and `-unit_test` will deploy and run on the device when executed (make sure that the `adb` executable is in your `PATH` for this to work).
77 |
78 | *Android Studio v3.5* can be used to launch and debug. After running *CMake* to build and generate everything, the *Android Studio* projects can be found under the `./build` directory.
79 |
80 | ### iOS
81 |
82 | For *iOS*, the steps are identical to the other platforms but due to code signing, you will need to perform the builds from *Xcode* manually. Note that this is only an issue if you attempt to use the tools or run the unit tests locally.
83 |
84 | ### Emscripten
85 |
86 | Emscripten support currently only has been tested on OS X and Linux. To use it, make sure to install a recent version of Emscripten SDK 1.39.11+.
87 |
88 | ## Commit message format
89 |
90 | This library uses the [angular.js message format](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#commits) and it is enforced with commit linting through every pull request.
91 |
92 | ## Authors
93 |
94 | * [Nicholas Frechette](https://github.com/nfrechette)
95 | * [Cody Jones](https://github.com/CodyDWJones)
96 |
97 | ## License, copyright, and code of conduct
98 |
99 | This project uses the [MIT license](LICENSE).
100 |
101 | Copyright (c) 2017 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
102 |
103 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
104 |
105 | ## Contributors ✨
106 |
107 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
108 |
109 |
110 |
111 |
112 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
127 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 0.9.99.{build}
2 |
3 | environment:
4 | PYTHON: "C:\\Python36-x64\\python.exe"
5 | matrix:
6 | - toolchain: msvc
7 | - toolchain: clang
8 |
9 | image:
10 | - Visual Studio 2015
11 | - Visual Studio 2017
12 |
13 | configuration:
14 | - Debug
15 | - Release
16 |
17 | platform:
18 | - x86
19 | - x64
20 | - arm64
21 |
22 | matrix:
23 | exclude:
24 | - image: Visual Studio 2015
25 | platform: arm64
26 | - image: Visual Studio 2015
27 | toolchain: clang
28 | - image: Visual Studio 2017
29 | toolchain: clang
30 |
31 |
32 | init:
33 | # Only run latest compiler on push, run everything on pull request
34 | - ps: if (!$env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_WORKER_IMAGE -ne "Visual Studio 2019") {Exit-AppveyorBuild}
35 |
36 | install:
37 | - cmd: >-
38 | git submodule update --init --recursive
39 |
40 | build_script:
41 | - cmd: >-
42 | .\tools\appveyor_ci.bat "%APPVEYOR_BUILD_WORKER_IMAGE%" %platform% %configuration% %toolchain% "%PYTHON%"
43 |
--------------------------------------------------------------------------------
/cmake/CMakeCompiler.cmake:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 |
3 | macro(setup_default_compiler_flags _project_name)
4 | if(MSVC)
5 | # Replace some default compiler switches and add new ones
6 | STRING(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Disable RTTI
7 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
8 | STRING(REPLACE "/W3" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Enable level 4 warnings
9 | else()
10 | if(MSVC_VERSION GREATER 1920)
11 | # VS2019 and above
12 | STRING(REPLACE "/W3" "/Wall" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Enable all warnings
13 | else()
14 | STRING(REPLACE "/W3" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Enable level 4 warnings
15 | endif()
16 | endif()
17 | target_compile_options(${_project_name} PRIVATE /Zi) # Add debug info
18 | target_compile_options(${_project_name} PRIVATE /Oi) # Generate intrinsic functions
19 | target_compile_options(${_project_name} PRIVATE /WX) # Treat warnings as errors
20 | target_compile_options(${_project_name} PRIVATE /MP) # Enable parallel compilation
21 |
22 | if(MSVC_VERSION GREATER 1900)
23 | # VS2017 and above
24 | target_compile_options(${_project_name} PRIVATE /permissive-)
25 | endif()
26 |
27 | # Disable various warnings that are harmless
28 | target_compile_options(${_project_name} PRIVATE /wd4514) # Unreferenced inline function removed
29 | target_compile_options(${_project_name} PRIVATE /wd4619) # No warning with specified number
30 | target_compile_options(${_project_name} PRIVATE /wd4820) # Padding added after data member
31 | target_compile_options(${_project_name} PRIVATE /wd4710) # Function not inlined
32 | target_compile_options(${_project_name} PRIVATE /wd4711) # Function selected for automatic inlining
33 | target_compile_options(${_project_name} PRIVATE /wd4738) # Storing 32-bit float in memory leads to rounding (x86)
34 | target_compile_options(${_project_name} PRIVATE /wd5045) # Spectre mitigation for memory load
35 |
36 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
37 | target_compile_options(${_project_name} PRIVATE -Wno-c++98-compat) # No need to support C++98
38 | target_compile_options(${_project_name} PRIVATE -Wno-c++98-compat-pedantic) # No need to support C++98
39 | endif()
40 |
41 | # Add linker flags
42 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG")
43 | else()
44 | # TODO: Handle OS X properly: https://stackoverflow.com/questions/5334095/cmake-multiarchitecture-compilation
45 | if(CPU_INSTRUCTION_SET MATCHES "x86")
46 | target_compile_options(${_project_name} PRIVATE "-m32")
47 | target_link_libraries(${_project_name} PRIVATE "-m32")
48 | elseif(CPU_INSTRUCTION_SET MATCHES "x64")
49 | target_compile_options(${_project_name} PRIVATE "-m64")
50 | target_link_libraries(${_project_name} PRIVATE "-m64")
51 | endif()
52 |
53 | target_compile_options(${_project_name} PRIVATE -Wall -Wextra) # Enable all warnings
54 | target_compile_options(${_project_name} PRIVATE -Wshadow) # Enable shadowing warnings
55 | target_compile_options(${_project_name} PRIVATE -Werror) # Treat warnings as errors
56 |
57 | # Disable various warnings that are harmless
58 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
59 | target_compile_options(${_project_name} PRIVATE -Wno-c++98-compat) # No need to support C++98
60 | endif()
61 |
62 | target_compile_options(${_project_name} PRIVATE -g) # Enable debug symbols
63 | endif()
64 | endmacro()
65 |
--------------------------------------------------------------------------------
/cmake/CMakePlatforms.cmake:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 |
3 | if(PLATFORM_NAME)
4 | return() # Already set
5 | endif()
6 |
7 | # Detect which platform we have
8 | if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
9 | set(PLATFORM_WINDOWS 1)
10 | set(PLATFORM_NAME "Windows")
11 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
12 | if(PLATFORM_IOS)
13 | set(PLATFORM_NAME "iOS")
14 | else()
15 | set(PLATFORM_OSX 1)
16 | set(PLATFORM_NAME "OS X")
17 | endif()
18 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
19 | set(PLATFORM_LINUX 1)
20 | set(PLATFORM_NAME "Linux")
21 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android")
22 | set(PLATFORM_ANDROID 1)
23 | set(PLATFORM_NAME "Android")
24 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Emscripten")
25 | set(PLATFORM_EMSCRIPTEN 1)
26 | set(PLATFORM_NAME "Emscripten")
27 | else()
28 | message(FATAL_ERROR "Unknown platform ${CMAKE_SYSTEM_NAME}!")
29 | endif()
30 |
31 | message(STATUS "Detected platform: ${PLATFORM_NAME}")
32 |
--------------------------------------------------------------------------------
/cmake/CMakeUtils.cmake:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 |
3 | # Create groups for the test source files, this creates the proper directory structure under the
4 | # Visual Studio filters
5 | macro(create_source_groups _source_files _relative_directory)
6 | foreach(_file IN ITEMS ${_source_files})
7 | get_filename_component(_file_path "${_file}" PATH)
8 | file(RELATIVE_PATH _file_path_rel "${_relative_directory}" "${_file_path}")
9 | string(REPLACE "/" "\\" _group_path "${_file_path_rel}")
10 | source_group("${_group_path}" FILES "${_file}")
11 | endforeach()
12 | endmacro()
13 |
--------------------------------------------------------------------------------
/cmake/Toolchain-Android.cmake:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 |
3 | # For Android, we just set the platform name as we won't be using CMake to build anything.
4 | # Instead Gradle is used through CMake.
5 |
6 | set(PLATFORM_ANDROID 1)
7 | set(PLATFORM_NAME "Android")
8 |
9 | # Remap our CPU instruction set
10 | if(CPU_INSTRUCTION_SET MATCHES "armv7")
11 | set(CPU_INSTRUCTION_SET "armeabi-v7a")
12 | elseif(CPU_INSTRUCTION_SET MATCHES "arm64")
13 | set(CPU_INSTRUCTION_SET "arm64-v8a")
14 | endif()
15 |
--------------------------------------------------------------------------------
/cmake/Toolchain-iOS.cmake:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 |
3 | set(CMAKE_SYSTEM_NAME Darwin)
4 |
5 | # Set here instead of CMakePlatforms.cmake since we can't distinguis otherwise
6 | set(PLATFORM_IOS 1)
7 |
8 | # Find and set the C/C++ compiler paths, cmake doesn't seem to do this properly on its own
9 | execute_process(COMMAND xcrun --sdk iphoneos --find clang OUTPUT_VARIABLE CMAKE_C_COMPILER OUTPUT_STRIP_TRAILING_WHITESPACE)
10 | execute_process(COMMAND xcrun --sdk iphoneos --find clang++ OUTPUT_VARIABLE CMAKE_CXX_COMPILER OUTPUT_STRIP_TRAILING_WHITESPACE)
11 |
12 | set(CMAKE_MACOSX_BUNDLE YES)
13 | set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
14 | set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "")
15 | set(CMAKE_OSX_SYSROOT iphoneos CACHE STRING "")
16 | set(CMAKE_OSX_ARCHITECTURES arm64 CACHE STRING "")
17 | set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET 17.0)
18 |
--------------------------------------------------------------------------------
/external/README.md:
--------------------------------------------------------------------------------
1 | # External dependencies
2 |
3 | Good news! There are no external dependencies needed by this library at runtime!
4 |
5 | ## Catch
6 |
7 | [Catch2 v2.13.7](https://github.com/catchorg/Catch2/releases/tag/v2.13.7) is used by our [unit tests](../tests). You will only need it if you run the unit tests and it is included as-is without modifications.
8 |
--------------------------------------------------------------------------------
/includes/sjson/error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | //////////////////////////////////////////////////////////////////////////
28 | // This library uses a simple system to handle asserts. Asserts are fatal and must terminate
29 | // otherwise the behavior is undefined if execution continues.
30 | //
31 | // A total of 4 behaviors are supported:
32 | // - We can print to stderr and abort
33 | // - We can throw and exception
34 | // - We can call a custom function
35 | // - Do nothing and strip the check at compile time (default behavior)
36 | //
37 | // Aborting:
38 | // In order to enable the aborting behavior, simply define the macro SJSON_CPP_ON_ASSERT_ABORT:
39 | // #define SJSON_CPP_ON_ASSERT_ABORT
40 | //
41 | // Throwing:
42 | // In order to enable the throwing behavior, simply define the macro SJSON_CPP_ON_ASSERT_THROW:
43 | // #define SJSON_CPP_ON_ASSERT_THROW
44 | // Note that the type of the exception thrown is sjson::runtime_assert.
45 | //
46 | // Custom function:
47 | // In order to enable the custom function calling behavior, define the macro SJSON_CPP_ON_ASSERT_CUSTOM
48 | // with the name of the function to call:
49 | // #define SJSON_CPP_ON_ASSERT_CUSTOM on_custom_assert_impl
50 | // Note that the function signature is as follow:
51 | // void on_custom_assert_impl(const char* expression, int line, const char* file, const char* format, ...) {}
52 | //
53 | // You can also define your own assert implementation by defining the SJSON_CPP_ASSERT macro as well:
54 | // #define SJSON_CPP_ON_ASSERT_CUSTOM
55 | // #define SJSON_CPP_ASSERT(expression, format, ...) checkf(expression, ANSI_TO_TCHAR(format), #__VA_ARGS__)
56 | //
57 | // [Custom String Format Specifier]
58 | // Note that if you use a custom function, you may need to override the SJSON_ASSERT_STRING_FORMAT_SPECIFIER
59 | // to properly handle ANSI/Unicode support. The C++11 standard does not support a way to say that '%s'
60 | // always means an ANSI string (with 'const char*' as type). MSVC does support '%hs' but other compilers
61 | // do not.
62 | //
63 | // No checks:
64 | // By default if no macro mentioned above is defined, all asserts will be stripped
65 | // at compile time.
66 | //////////////////////////////////////////////////////////////////////////
67 |
68 | // See [Custom String Format Specifier] for details
69 | #if !defined(SJSON_ASSERT_STRING_FORMAT_SPECIFIER)
70 | #define SJSON_ASSERT_STRING_FORMAT_SPECIFIER "%s"
71 | #endif
72 |
73 | #if defined(SJSON_CPP_ON_ASSERT_ABORT)
74 |
75 | #include "sjson/version.h"
76 |
77 | #include
78 | #include
79 | #include
80 |
81 | namespace sjson
82 | {
83 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
84 |
85 | namespace error_impl
86 | {
87 | [[noreturn]] inline void on_assert_abort(const char* expression, int line, const char* file, const char* format, ...)
88 | {
89 | (void)expression;
90 | (void)line;
91 | (void)file;
92 |
93 | va_list args;
94 | va_start(args, format);
95 |
96 | std::vfprintf(stderr, format, args);
97 | std::fprintf(stderr, "\n");
98 |
99 | va_end(args);
100 |
101 | std::abort();
102 | }
103 | }
104 |
105 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
106 | }
107 |
108 | #define SJSON_CPP_ASSERT(expression, format, ...) do { if (!(expression)) SJSON_CPP_IMPL_NAMESPACE::error_impl::on_assert_abort(#expression, __LINE__, __FILE__, (format), ## __VA_ARGS__); } while (false)
109 | #define SJSON_CPP_HAS_ASSERT_CHECKS
110 |
111 | #elif defined(SJSON_CPP_ON_ASSERT_THROW)
112 |
113 | #include "sjson/version.h"
114 |
115 | #include
116 | #include
117 | #include
118 | #include
119 |
120 | namespace sjson
121 | {
122 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
123 |
124 | class runtime_assert final : public std::runtime_error
125 | {
126 | runtime_assert() = delete; // Default constructor not needed
127 |
128 | using std::runtime_error::runtime_error; // Inherit constructors
129 | };
130 |
131 | namespace error_impl
132 | {
133 | [[noreturn]] inline void on_assert_throw(const char* expression, int line, const char* file, const char* format, ...)
134 | {
135 | (void)expression;
136 | (void)line;
137 | (void)file;
138 |
139 | constexpr int buffer_size = 1 * 1024;
140 | char buffer[buffer_size];
141 |
142 | va_list args;
143 | va_start(args, format);
144 |
145 | const int count = vsnprintf(buffer, buffer_size, format, args);
146 |
147 | va_end(args);
148 |
149 | if (count >= 0 && count < buffer_size)
150 | throw runtime_assert(std::string(&buffer[0], static_cast(count)));
151 | else
152 | throw runtime_assert("Failed to format assert message!\n");
153 | }
154 | }
155 |
156 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
157 | }
158 |
159 | #define SJSON_CPP_ASSERT(expression, format, ...) do { if (!(expression)) SJSON_CPP_IMPL_NAMESPACE::error_impl::on_assert_throw(#expression, __LINE__, __FILE__, (format), ## __VA_ARGS__); } while(false)
160 | #define SJSON_CPP_HAS_ASSERT_CHECKS
161 |
162 | #elif defined(SJSON_CPP_ON_ASSERT_CUSTOM)
163 |
164 | #if !defined(SJSON_CPP_ASSERT)
165 | #define SJSON_CPP_ASSERT(expression, format, ...) do { if (!(expression)) SJSON_CPP_ON_ASSERT_CUSTOM(#expression, __LINE__, __FILE__, (format), ## __VA_ARGS__); } while(false)
166 | #endif
167 |
168 | #define SJSON_CPP_HAS_ASSERT_CHECKS
169 |
170 | #else
171 |
172 | #define SJSON_CPP_ASSERT(expression, format, ...) ((void)0)
173 |
174 | #endif
175 |
--------------------------------------------------------------------------------
/includes/sjson/fwd.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2022 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | #include "sjson/version.h"
28 |
29 | ////////////////////////////////////////////////////////////////////////////////
30 | // This header provides forward declarations for all public sjson-cpp types.
31 | // Forward declaring symbols from a 3rd party library is a bad idea, use this
32 | // header instead.
33 | // See also: https://blog.libtorrent.org/2017/12/forward-declarations-and-abi/
34 | ////////////////////////////////////////////////////////////////////////////////
35 |
36 | namespace sjson
37 | {
38 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
39 |
40 | // Core
41 | class runtime_assert;
42 | class StringView;
43 |
44 | // Parser
45 | struct ParserError;
46 | struct ParserState;
47 | class Parser;
48 |
49 | // Writer
50 | class StreamWriter;
51 | class FileStreamWriter;
52 | class ArrayWriter;
53 | class ObjectWriter;
54 | class Writer;
55 |
56 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
57 | }
58 |
--------------------------------------------------------------------------------
/includes/sjson/impl/bit_cast.impl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2023 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | #include "sjson/version.h"
28 |
29 | #if defined(__cplusplus) && __cplusplus >= 202002L
30 | #include
31 | #elif defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
32 | #include
33 | #endif
34 |
35 | namespace sjson
36 | {
37 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
38 |
39 | namespace sjson_impl
40 | {
41 | //////////////////////////////////////////////////////////////////////////
42 | // C++20 introduced std::bit_cast which is safer than reinterpret_cast
43 | //////////////////////////////////////////////////////////////////////////
44 |
45 | #if defined(__cplusplus) && __cplusplus >= 202002L
46 | using std::bit_cast;
47 | #elif defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
48 | using std::bit_cast;
49 | #else
50 | template
51 | constexpr dest_type_t bit_cast(src_type_t input) noexcept
52 | {
53 | return reinterpret_cast(input);
54 | }
55 | #endif
56 | }
57 |
58 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
59 | }
60 |
--------------------------------------------------------------------------------
/includes/sjson/impl/cstdlib.impl.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | #include "sjson/version.h"
28 |
29 | //////////////////////////////////////////////////////////////////////////
30 | // The Android NDK r10 and possibly earlier used a STD lib that poorly supported C++11.
31 | // As such, it is necessary to polyfill a few missing things.
32 | //////////////////////////////////////////////////////////////////////////
33 | #if defined(__GNUG__) && defined(__ANDROID__) && __GNUC__ < 5
34 | #define SJSON_CPP_IMPL_POLYFILL_STD
35 | #endif
36 |
37 | #if defined(SJSON_CPP_IMPL_POLYFILL_STD)
38 | #include
39 | #else
40 | #include
41 | #endif
42 |
43 | namespace sjson
44 | {
45 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
46 |
47 | namespace sjson_impl
48 | {
49 | #if defined(SJSON_CPP_IMPL_POLYFILL_STD)
50 | // We need to polyfill these, bring the C version into our namespace
51 | using ::strtoull;
52 | using ::strtoll;
53 | using ::strtof;
54 | #else
55 | // These properly exist in the C++ version, use them
56 | using std::strtoull;
57 | using std::strtoll;
58 | using std::strtof;
59 | #endif
60 | }
61 |
62 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
63 | }
64 |
--------------------------------------------------------------------------------
/includes/sjson/parser_error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2017 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | #include "sjson/version.h"
28 |
29 | #include
30 |
31 | namespace sjson
32 | {
33 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
34 |
35 | struct ParserError
36 | {
37 | enum : uint32_t
38 | {
39 | None,
40 | InputTruncated,
41 | OpeningBraceExpected,
42 | ClosingBraceExpected,
43 | EqualSignExpected,
44 | OpeningBracketExpected,
45 | ClosingBracketExpected,
46 | CommaExpected,
47 | CommentBeginsIncorrectly,
48 | CannotUseQuotationMarkInUnquotedString,
49 | KeyExpected,
50 | IncorrectKey,
51 | TrueOrFalseExpected,
52 | QuotationMarkExpected,
53 | NumberExpected,
54 | NumberIsTooLong,
55 | InvalidNumber,
56 | NumberCouldNotBeConverted,
57 | UnexpectedContentAtEnd,
58 |
59 | Last
60 | };
61 |
62 | uint32_t error = None;
63 | uint32_t line = 0;
64 | uint32_t column = 0;
65 |
66 | ParserError() = default;
67 | ParserError(const ParserError&) = default;
68 | ParserError& operator=(const ParserError&) = default;
69 |
70 | virtual ~ParserError() = default;
71 |
72 | virtual const char* get_description() const
73 | {
74 | switch (error)
75 | {
76 | case None:
77 | return "None";
78 | case InputTruncated:
79 | return "The file ended sooner than expected";
80 | case OpeningBraceExpected:
81 | return "An opening { is expected here";
82 | case ClosingBraceExpected:
83 | return "A closing } is expected here";
84 | case EqualSignExpected:
85 | return "An equal sign is expected here";
86 | case OpeningBracketExpected:
87 | return "An opening [ is expected here";
88 | case ClosingBracketExpected:
89 | return "A closing ] is expected here";
90 | case CommaExpected:
91 | return "A comma is expected here";
92 | case CommentBeginsIncorrectly:
93 | return "Comments must start with either // or /*";
94 | case CannotUseQuotationMarkInUnquotedString:
95 | return "Quotation marks cannot be used in unquoted strings";
96 | case KeyExpected:
97 | return "The name of a key is expected here";
98 | case IncorrectKey:
99 | return "A different key is expected here";
100 | case TrueOrFalseExpected:
101 | return "Only the literals true or false are allowed here";
102 | case QuotationMarkExpected:
103 | return "A quotation mark is expected here";
104 | case NumberExpected:
105 | return "A number is expected here";
106 | case NumberIsTooLong:
107 | return "The number is too long; increase Parser::MAX_NUMBER_LENGTH";
108 | case InvalidNumber:
109 | return "This number has an invalid format";
110 | case NumberCouldNotBeConverted:
111 | return "This number could not be converted";
112 | case UnexpectedContentAtEnd:
113 | return "There should not be any more content in this file";
114 | default:
115 | return "Unknown error";
116 | }
117 | }
118 | };
119 |
120 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
121 | }
122 |
--------------------------------------------------------------------------------
/includes/sjson/parser_state.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2017 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | #include "sjson/parser_error.h"
28 | #include "sjson/version.h"
29 |
30 | #include
31 | #include
32 |
33 | namespace sjson
34 | {
35 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
36 |
37 | struct ParserState
38 | {
39 | ParserState(const char* input, size_t input_length)
40 | : offset(0)
41 | , line(1)
42 | , column(1)
43 | , symbol(input_length > 0 ? input[0] : '\0')
44 | {
45 | }
46 |
47 | size_t offset;
48 | uint32_t line;
49 | uint32_t column;
50 | char symbol;
51 |
52 | ParserError error;
53 | };
54 |
55 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
56 | }
57 |
--------------------------------------------------------------------------------
/includes/sjson/string_view.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2017 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | #include "sjson/error.h"
28 | #include "sjson/version.h"
29 |
30 | #include
31 | #include
32 |
33 | namespace sjson
34 | {
35 | SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
36 |
37 | //////////////////////////////////////////////////////////////////////////
38 | // A StringView is just a pointer to a string and an associated length.
39 | // It does NOT own the memory and no allocation or deallocation ever takes place.
40 | // An empty StringView() is equal to a StringView("") of the empty string.
41 | // It is not legal to create a StringView that contains multiple NULL terminators
42 | // and if you do so, the behavior is undefined.
43 | //
44 | // Two different StringViews are equal if the strings pointed to are equal.
45 | // They do not need to be pointing to the same physical string.
46 | // StringView("this") == StringView("this is fun", 4)
47 | //
48 | // The string pointed to is immutable.
49 | //////////////////////////////////////////////////////////////////////////
50 | class StringView
51 | {
52 | public:
53 | constexpr StringView()
54 | : m_c_str(nullptr)
55 | , m_length(0)
56 | {}
57 |
58 | StringView(const char* str, size_t length)
59 | : m_c_str(str)
60 | , m_length(length)
61 | {
62 | #if defined(SJSON_CPP_USE_ERROR_CHECKS) && !defined(NDEBUG)
63 | for (size_t i = 0; i < length; ++i)
64 | SJSON_CPP_ASSERT(str[i] != '\0', "StringView cannot contain NULL terminators");
65 | #endif
66 | }
67 |
68 | StringView(const char* str)
69 | : m_c_str(str)
70 | , m_length(str == nullptr ? 0 : std::strlen(str))
71 | {}
72 |
73 | StringView& operator=(const char* str)
74 | {
75 | m_c_str = str;
76 | m_length = str == nullptr ? 0 : std::strlen(str);
77 | return *this;
78 | }
79 |
80 | constexpr const char* c_str() const { return m_length == 0 ? "" : m_c_str; }
81 | constexpr size_t size() const { return m_length; }
82 | constexpr bool empty() const { return m_length == 0; }
83 |
84 | bool operator==(const char* str) const
85 | {
86 | const size_t length = str == nullptr ? 0 : std::strlen(str);
87 | if (m_length != length)
88 | return false;
89 |
90 | if (m_c_str == str || length == 0)
91 | return true;
92 |
93 | return std::memcmp(m_c_str, str, length) == 0;
94 | }
95 |
96 | bool operator!=(const char* str) const { return !(*this == str); }
97 |
98 | bool operator==(const StringView& other) const
99 | {
100 | if (m_length != other.m_length)
101 | return false;
102 |
103 | if (m_c_str == other.m_c_str || m_length == 0)
104 | return true;
105 |
106 | return std::memcmp(m_c_str, other.m_c_str, m_length) == 0;
107 | }
108 |
109 | bool operator !=(const StringView& other) const { return !(*this == other); }
110 |
111 | char operator[](size_t offset) const
112 | {
113 | SJSON_CPP_ASSERT(offset < m_length, "Invalid offset");
114 | return m_c_str[offset];
115 | }
116 |
117 | private:
118 | const char* m_c_str;
119 | size_t m_length;
120 | };
121 |
122 | SJSON_CPP_IMPL_VERSION_NAMESPACE_END
123 | }
124 |
--------------------------------------------------------------------------------
/includes/sjson/version.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | ////////////////////////////////////////////////////////////////////////////////
4 | // The MIT License (MIT)
5 | //
6 | // Copyright (c) 2022 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | ////////////////////////////////////////////////////////////////////////////////
26 |
27 | ////////////////////////////////////////////////////////////////////////////////
28 | // Macros to detect the sjson-cpp version
29 | ////////////////////////////////////////////////////////////////////////////////
30 |
31 | #define SJSON_CPP_VERSION_MAJOR 0
32 | #define SJSON_CPP_VERSION_MINOR 9
33 | #define SJSON_CPP_VERSION_PATCH 99
34 |
35 | ////////////////////////////////////////////////////////////////////////////////
36 | // In order to allow multiple versions of this library to coexist side by side
37 | // within the same executable/library, the symbols have to be unique per version.
38 | // We achieve this by using a versioned namespace that we optionally inline.
39 | // To disable namespace inlining, define SJSON_CPP_NO_INLINE_NAMESPACE before including
40 | // any sjson-cpp header. To disable the versioned namespace altogether,
41 | // define SJSON_CPP_NO_VERSION_NAMESPACE before including any sjson-cpp header.
42 | ////////////////////////////////////////////////////////////////////////////////
43 |
44 | #if !defined(SJSON_CPP_NO_VERSION_NAMESPACE)
45 | #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER == 1900
46 | // VS2015 struggles with type resolution when inline namespaces are used
47 | // For that reason, we disable it explicitly
48 | #define SJSON_CPP_NO_VERSION_NAMESPACE
49 | #endif
50 | #endif
51 |
52 | // Force macro expansion to concatenate namespace identifier
53 | #define SJSON_CPP_IMPL_VERSION_CONCAT_IMPL(prefix, major, minor, patch) prefix ## major ## minor ## patch
54 | #define SJSON_CPP_IMPL_VERSION_CONCAT(prefix, major, minor, patch) SJSON_CPP_IMPL_VERSION_CONCAT_IMPL(prefix, major, minor, patch)
55 |
56 | // Name of the namespace, e.g. v082
57 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_NAME SJSON_CPP_IMPL_VERSION_CONCAT(v, SJSON_CPP_VERSION_MAJOR, SJSON_CPP_VERSION_MINOR, SJSON_CPP_VERSION_PATCH)
58 |
59 | // Because this is being introduced in a patch release, as caution, it is disabled
60 | // by default. It does break ABI if host runtimes forward declare types but that
61 | // is something they shouldn't do with a 3rd party library. Now, we offer forward
62 | // declaration headers to help prepare the migration in the next minor release.
63 | #if defined(SJSON_CPP_NO_VERSION_NAMESPACE) || !defined(SJSON_CPP_ENABLE_VERSION_NAMESPACE)
64 | // Namespace is inlined, its usage does not need to be qualified with the
65 | // full version everywhere
66 | #define SJSON_CPP_IMPL_NAMESPACE sjson
67 |
68 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN
69 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_END
70 | #elif defined(SJSON_CPP_NO_INLINE_NAMESPACE)
71 | // Namespace won't be inlined, its usage will have to be qualified with the
72 | // full version everywhere
73 | #define SJSON_CPP_IMPL_NAMESPACE sjson::SJSON_CPP_IMPL_VERSION_NAMESPACE_NAME
74 |
75 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN \
76 | namespace SJSON_CPP_IMPL_VERSION_NAMESPACE_NAME \
77 | {
78 |
79 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_END \
80 | }
81 | #else
82 | // Namespace is inlined, its usage does not need to be qualified with the
83 | // full version everywhere
84 | #define SJSON_CPP_IMPL_NAMESPACE sjson
85 |
86 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_BEGIN \
87 | inline namespace SJSON_CPP_IMPL_VERSION_NAMESPACE_NAME \
88 | {
89 |
90 | #define SJSON_CPP_IMPL_VERSION_NAMESPACE_END \
91 | }
92 | #endif
93 |
--------------------------------------------------------------------------------
/make.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import multiprocessing
3 | import os
4 | import platform
5 | import shutil
6 | import subprocess
7 | import sys
8 |
9 | def parse_argv():
10 | parser = argparse.ArgumentParser(add_help=False)
11 |
12 | actions = parser.add_argument_group(title='Actions', description='If no action is specified, on Windows, OS X, and Linux the solution/make files are generated. Multiple actions can be used simultaneously.')
13 | actions.add_argument('-build', action='store_true')
14 | actions.add_argument('-clean', action='store_true')
15 | actions.add_argument('-clean_only', action='store_true')
16 | actions.add_argument('-unit_test', action='store_true')
17 |
18 | target = parser.add_argument_group(title='Target')
19 | target.add_argument('-compiler', choices=['vs2015', 'vs2017', 'vs2019', 'vs2019-clang', 'vs2022', 'vs2022-clang', 'android', 'clang4', 'clang5', 'clang6', 'clang7', 'clang8', 'clang9', 'clang10', 'clang11', 'clang12', 'clang13', 'clang14', 'clang15', 'clang16', 'clang17', 'clang18', 'gcc4.8', 'gcc4.9', 'gcc5', 'gcc6', 'gcc7', 'gcc8', 'gcc9', 'gcc10', 'gcc11', 'gcc12', 'gcc13', 'osx', 'ios', 'emscripten'], help='Defaults to the host system\'s default compiler')
20 | target.add_argument('-config', choices=['Debug', 'Release'], type=str.capitalize)
21 | target.add_argument('-cpu', choices=['x86', 'x64', 'armv7', 'arm64', 'wasm'], help='Defaults to the host system\'s architecture')
22 | target.add_argument('-cpp_version', choices=['11', '14', '17', '20'], help='Defaults to C++11')
23 |
24 | misc = parser.add_argument_group(title='Miscellaneous')
25 | misc.add_argument('-num_threads', help='No. to use while compiling')
26 | misc.add_argument('-tests_matching', help='Only run tests whose names match this regex')
27 | misc.add_argument('-ci', action='store_true', help='Whether or not this is a Continuous Integration build')
28 | misc.add_argument('-help', action='help', help='Display this usage information')
29 |
30 | num_threads = multiprocessing.cpu_count()
31 | if platform.system() == 'Linux' and sys.version_info >= (3, 4):
32 | num_threads = len(os.sched_getaffinity(0))
33 | if not num_threads or num_threads == 0:
34 | num_threads = 4
35 |
36 | parser.set_defaults(build=False, clean=False, clean_only=False, unit_test=False, compiler=None, config='Release', cpu=None, cpp_version='11', num_threads=num_threads, tests_matching='')
37 |
38 | args = parser.parse_args()
39 |
40 | is_arm64_cpu = False
41 | if platform.machine() == 'arm64' or platform.machine() == 'aarch64':
42 | is_arm64_cpu = True
43 |
44 | # Sanitize and validate our options
45 | if args.compiler == 'android':
46 | if not args.cpu:
47 | args.cpu = 'arm64'
48 |
49 | if not platform.system() == 'Windows':
50 | print('Android is only supported on Windows')
51 | sys.exit(1)
52 |
53 | if not args.cpu in ['armv7', 'arm64']:
54 | print('{} cpu architecture not in supported list [armv7, arm64] for Android'.format(args.cpu))
55 | sys.exit(1)
56 | elif args.compiler == 'ios':
57 | if not args.cpu:
58 | args.cpu = 'arm64'
59 |
60 | if not platform.system() == 'Darwin':
61 | print('iOS is only supported on OS X')
62 | sys.exit(1)
63 |
64 | if args.unit_test:
65 | print('Unit tests cannot run from the command line on iOS')
66 | sys.exit(1)
67 |
68 | if not args.cpu in ['arm64']:
69 | print('{} cpu architecture not in supported list [arm64] for iOS'.format(args.cpu))
70 | sys.exit(1)
71 | elif args.compiler == 'emscripten':
72 | if not args.cpu:
73 | args.cpu = 'wasm'
74 |
75 | if not platform.system() == 'Darwin' and not platform.system() == 'Linux':
76 | print('Emscripten is only supported on OS X and Linux')
77 | sys.exit(1)
78 |
79 | if not args.cpu in ['wasm']:
80 | print('{} cpu architecture not in supported list [wasm] for Emscripten'.format(args.cpu))
81 | sys.exit(1)
82 | else:
83 | if not args.cpu:
84 | if is_arm64_cpu:
85 | args.cpu = 'arm64'
86 | else:
87 | args.cpu = 'x64'
88 |
89 | if args.cpu == 'arm64':
90 | is_arm_supported = False
91 |
92 | # Cross compilation
93 | if args.compiler in ['vs2017', 'vs2019', 'vs2022', 'ios', 'android']:
94 | is_arm_supported = True
95 |
96 | # Native compilation
97 | if platform.system() == 'Darwin' and is_arm64_cpu:
98 | is_arm_supported = True
99 | elif platform.system() == 'Linux' and is_arm64_cpu:
100 | is_arm_supported = True
101 |
102 | if not is_arm_supported:
103 | print('arm64 is only supported with VS2017, VS2019, OS X (M1 processors), Linux, Android, and iOS')
104 | sys.exit(1)
105 | elif args.cpu == 'armv7':
106 | if not args.compiler == 'android':
107 | print('armv7 is only supported with Android')
108 | sys.exit(1)
109 | elif args.cpu == 'wasm':
110 | if not args.compiler == 'emscripten':
111 | print('wasm is only supported with Emscripten')
112 | sys.exit(1)
113 |
114 | if platform.system() == 'Darwin' and args.cpu == 'x86':
115 | result = subprocess.check_output(['xcodebuild', '-version']).decode("utf-8")
116 | if 'Xcode 11' in result:
117 | print('Versions of Xcode 11 and up no longer support x86')
118 | sys.exit(1)
119 |
120 | return args
121 |
122 | def get_generator(compiler, cpu):
123 | if compiler == None:
124 | return None
125 |
126 | if platform.system() == 'Windows':
127 | if compiler == 'vs2015':
128 | if cpu == 'x86':
129 | return 'Visual Studio 14'
130 | elif cpu == 'x64':
131 | return 'Visual Studio 14 Win64'
132 | elif compiler == 'vs2017':
133 | if cpu == 'x86':
134 | return 'Visual Studio 15'
135 | elif cpu == 'x64':
136 | return 'Visual Studio 15 Win64'
137 | elif cpu == 'arm64':
138 | # VS2017 ARM/ARM64 support only works with cmake 3.13 and up and the architecture must be specified with
139 | # the -A cmake switch
140 | return 'Visual Studio 15 2017'
141 | elif compiler == 'vs2019' or compiler == 'vs2019-clang':
142 | return 'Visual Studio 16 2019'
143 | elif compiler == 'vs2022' or compiler == 'vs2022-clang':
144 | return 'Visual Studio 17 2022'
145 | elif compiler == 'android':
146 | # For Android, we use the default generator since we don't build with CMake
147 | return None
148 | elif platform.system() == 'Darwin':
149 | if compiler == 'osx' or compiler == 'ios':
150 | return 'Xcode'
151 | elif compiler == 'emscripten':
152 | # Emscripten uses the default generator
153 | return None
154 | elif platform.system() == 'Linux':
155 | if compiler == 'emscripten':
156 | # Emscripten uses the default generator
157 | return None
158 |
159 | return 'Unix Makefiles'
160 |
161 | print('Unknown compiler: {}'.format(compiler))
162 | print('See help with: python make.py -help')
163 | sys.exit(1)
164 |
165 | def get_architecture(compiler, cpu):
166 | if compiler == None:
167 | return None
168 |
169 | if platform.system() == 'Windows':
170 | if compiler == 'vs2017':
171 | if cpu == 'arm64':
172 | return 'ARM64'
173 |
174 | is_modern_vs = False
175 | if compiler == 'vs2019' or compiler == 'vs2019-clang':
176 | is_modern_vs = True
177 | elif compiler == 'vs2022' or compiler == 'vs2022-clang':
178 | is_modern_vs = True
179 |
180 | if is_modern_vs:
181 | if cpu == 'x86':
182 | return 'Win32'
183 | else:
184 | return cpu
185 |
186 | # This compiler/cpu pair does not need the architecture switch
187 | return None
188 |
189 | def get_toolchain(compiler, cmake_script_dir):
190 | if platform.system() == 'Windows' and compiler == 'android':
191 | return os.path.join(cmake_script_dir, 'Toolchain-Android.cmake')
192 | elif platform.system() == 'Darwin' and compiler == 'ios':
193 | return os.path.join(cmake_script_dir, 'Toolchain-iOS.cmake')
194 |
195 | # No toolchain
196 | return None
197 |
198 | def set_compiler_env(compiler, args):
199 | if platform.system() == 'Linux':
200 | if compiler == 'clang4':
201 | os.environ['CC'] = 'clang-4.0'
202 | os.environ['CXX'] = 'clang++-4.0'
203 | elif compiler == 'clang5':
204 | os.environ['CC'] = 'clang-5.0'
205 | os.environ['CXX'] = 'clang++-5.0'
206 | elif compiler == 'clang6':
207 | os.environ['CC'] = 'clang-6.0'
208 | os.environ['CXX'] = 'clang++-6.0'
209 | elif compiler == 'clang7':
210 | os.environ['CC'] = 'clang-7'
211 | os.environ['CXX'] = 'clang++-7'
212 | elif compiler == 'clang8':
213 | os.environ['CC'] = 'clang-8'
214 | os.environ['CXX'] = 'clang++-8'
215 | elif compiler == 'clang9':
216 | os.environ['CC'] = 'clang-9'
217 | os.environ['CXX'] = 'clang++-9'
218 | elif compiler == 'clang10':
219 | os.environ['CC'] = 'clang-10'
220 | os.environ['CXX'] = 'clang++-10'
221 | elif compiler == 'clang11':
222 | os.environ['CC'] = 'clang-11'
223 | os.environ['CXX'] = 'clang++-11'
224 | elif compiler == 'clang12':
225 | os.environ['CC'] = 'clang-12'
226 | os.environ['CXX'] = 'clang++-12'
227 | elif compiler == 'clang13':
228 | os.environ['CC'] = 'clang-13'
229 | os.environ['CXX'] = 'clang++-13'
230 | elif compiler == 'clang14':
231 | os.environ['CC'] = 'clang-14'
232 | os.environ['CXX'] = 'clang++-14'
233 | elif compiler == 'clang15':
234 | os.environ['CC'] = 'clang-15'
235 | os.environ['CXX'] = 'clang++-15'
236 | elif compiler == 'clang16':
237 | os.environ['CC'] = 'clang-16'
238 | os.environ['CXX'] = 'clang++-16'
239 | elif compiler == 'clang17':
240 | os.environ['CC'] = 'clang-17'
241 | os.environ['CXX'] = 'clang++-17'
242 | elif compiler == 'clang18':
243 | os.environ['CC'] = 'clang-18'
244 | os.environ['CXX'] = 'clang++-18'
245 | elif compiler == 'gcc4.8':
246 | os.environ['CC'] = 'gcc-4.8'
247 | os.environ['CXX'] = 'g++-4.8'
248 | elif compiler == 'gcc4.9':
249 | os.environ['CC'] = 'gcc-4.9'
250 | os.environ['CXX'] = 'g++-4.9'
251 | elif compiler == 'gcc5':
252 | os.environ['CC'] = 'gcc-5'
253 | os.environ['CXX'] = 'g++-5'
254 | elif compiler == 'gcc6':
255 | os.environ['CC'] = 'gcc-6'
256 | os.environ['CXX'] = 'g++-6'
257 | elif compiler == 'gcc7':
258 | os.environ['CC'] = 'gcc-7'
259 | os.environ['CXX'] = 'g++-7'
260 | elif compiler == 'gcc8':
261 | os.environ['CC'] = 'gcc-8'
262 | os.environ['CXX'] = 'g++-8'
263 | elif compiler == 'gcc9':
264 | os.environ['CC'] = 'gcc-9'
265 | os.environ['CXX'] = 'g++-9'
266 | elif compiler == 'gcc10':
267 | os.environ['CC'] = 'gcc-10'
268 | os.environ['CXX'] = 'g++-10'
269 | elif compiler == 'gcc11':
270 | os.environ['CC'] = 'gcc-11'
271 | os.environ['CXX'] = 'g++-11'
272 | elif compiler == 'gcc12':
273 | os.environ['CC'] = 'gcc-12'
274 | os.environ['CXX'] = 'g++-12'
275 | elif compiler == 'gcc13':
276 | os.environ['CC'] = 'gcc-13'
277 | os.environ['CXX'] = 'g++-13'
278 | elif compiler == 'emscripten':
279 | # Nothing to do for Emscripten
280 | return
281 | else:
282 | print('Unknown compiler: {}'.format(compiler))
283 | print('See help with: python make.py -help')
284 | sys.exit(1)
285 |
286 | def do_generate_solution(build_dir, cmake_script_dir, args):
287 | compiler = args.compiler
288 | cpu = args.cpu
289 | config = args.config
290 |
291 | if compiler:
292 | set_compiler_env(compiler, args)
293 |
294 | extra_switches = ['--no-warn-unused-cli']
295 | extra_switches.append('-DCPU_INSTRUCTION_SET:STRING={}'.format(cpu))
296 | extra_switches.append('-DCMAKE_CXX_STANDARD:STRING={}'.format(args.cpp_version))
297 |
298 | if platform.system() == 'Windows':
299 | if os.path.sep == '\\':
300 | # Native Windows
301 | extra_switches
302 | else:
303 | # MSYS2 or Cygwin
304 | extra_switches.append('-DCMAKE_BUILD_TYPE={}'.format(config.upper()))
305 | else:
306 | extra_switches.append('-DCMAKE_BUILD_TYPE={}'.format(config.upper()))
307 |
308 | if platform.system() == 'Darwin' and compiler == 'ios' and args.ci:
309 | # Disable code signing for CI iOS builds since we just test compilation
310 | extra_switches.append('-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED=NO')
311 | extra_switches.append('-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED=NO')
312 |
313 | toolchain = get_toolchain(compiler, cmake_script_dir)
314 | if toolchain:
315 | extra_switches.append('-DCMAKE_TOOLCHAIN_FILE={}'.format(toolchain))
316 |
317 | # Generate IDE solution
318 | print('Generating build files ...')
319 | if compiler == 'emscripten':
320 | cmake_cmd = 'emcmake cmake .. -DCMAKE_INSTALL_PREFIX="{}" {}'.format(build_dir, ' '.join(extra_switches))
321 | else:
322 | cmake_generator = get_generator(compiler, cpu)
323 | if not cmake_generator:
324 | print('Using default generator')
325 | else:
326 | generator_suffix = ''
327 | if compiler == 'vs2019-clang' or compiler == 'vs2022-clang':
328 | extra_switches.append('-T ClangCL')
329 | generator_suffix = 'Clang CL'
330 |
331 | print('Using generator: {} {}'.format(cmake_generator, generator_suffix))
332 | extra_switches.append('-G "{}"'.format(cmake_generator))
333 |
334 | cmake_arch = get_architecture(compiler, cpu)
335 | if cmake_arch:
336 | print('Using architecture: {}'.format(cmake_arch))
337 | extra_switches.append('-A {}'.format(cmake_arch))
338 |
339 | cmake_cmd = 'cmake .. -DCMAKE_INSTALL_PREFIX="{}" {}'.format(build_dir, ' '.join(extra_switches))
340 |
341 | result = subprocess.call(cmake_cmd, shell=True)
342 | if result != 0:
343 | sys.exit(result)
344 |
345 | def do_build(args):
346 | config = args.config
347 |
348 | print('Building ...')
349 | cmake_cmd = 'cmake --build .'
350 | if platform.system() == 'Windows':
351 | if args.compiler == 'android':
352 | cmake_cmd += ' --config {}'.format(config)
353 | else:
354 | if os.path.sep == '\\':
355 | # Native Windows
356 | cmake_cmd += ' --config {} --target INSTALL'.format(config)
357 | else:
358 | # MSYS2 or Cygwin
359 | cmake_cmd += ' --config {} --target install'.format(config)
360 | elif platform.system() == 'Darwin':
361 | if args.compiler == 'ios':
362 | cmake_cmd += ' --config {}'.format(config)
363 | else:
364 | cmake_cmd += ' --config {} --target install'.format(config)
365 | else:
366 | cmake_cmd += ' --target install'
367 |
368 | result = subprocess.call(cmake_cmd, shell=True)
369 | if result != 0:
370 | sys.exit(result)
371 |
372 | def do_tests_android(build_dir, args):
373 | # Switch our working directory to where we built everything
374 | working_dir = os.path.join(build_dir, 'tests', 'main_android')
375 | os.chdir(working_dir)
376 |
377 | gradlew_exe = os.path.join(build_dir, '..', 'tests', 'main_android', 'gradlew.bat')
378 |
379 | # We uninstall first and then install
380 | if args.config == 'Debug':
381 | install_cmd = 'uninstallAll installDebug'
382 | elif args.config == 'Release':
383 | install_cmd = 'uninstallAll installRelease'
384 |
385 | # Install our app
386 | test_cmd = '"{}" {}'.format(gradlew_exe, install_cmd)
387 | result = subprocess.call(test_cmd, shell=True)
388 | if result != 0:
389 | sys.exit(result)
390 |
391 | # Execute through ADB
392 | run_cmd = 'adb shell am start -n "com.sjson.unit_tests/com.sjson.unit_tests.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER'
393 | result = subprocess.call(run_cmd, shell=True)
394 | if result != 0:
395 | sys.exit(result)
396 |
397 | # Restore working directory
398 | os.chdir(build_dir)
399 |
400 | def do_tests_cmake(args):
401 | ctest_cmd = 'ctest --output-on-failure --parallel {}'.format(args.num_threads)
402 |
403 | if platform.system() == 'Windows' or platform.system() == 'Darwin':
404 | ctest_cmd += ' -C {}'.format(args.config)
405 | if args.tests_matching:
406 | ctest_cmd += ' --tests-regex {}'.format(args.tests_matching)
407 |
408 | result = subprocess.call(ctest_cmd, shell=True)
409 | if result != 0:
410 | sys.exit(result)
411 |
412 | def do_tests(build_dir, args):
413 | print('Running unit tests ...')
414 |
415 | if args.compiler == 'android':
416 | do_tests_android(build_dir, args)
417 | else:
418 | do_tests_cmake(args)
419 |
420 | if __name__ == "__main__":
421 | args = parse_argv()
422 |
423 | build_dir = os.path.join(os.getcwd(), 'build')
424 | cmake_script_dir = os.path.join(os.getcwd(), 'cmake')
425 |
426 | is_clean_requested = args.clean or args.clean_only
427 | if is_clean_requested and os.path.exists(build_dir):
428 | print('Cleaning previous build ...')
429 | shutil.rmtree(build_dir)
430 |
431 | if args.clean_only:
432 | sys.exit(0)
433 |
434 | if not os.path.exists(build_dir):
435 | os.makedirs(build_dir)
436 |
437 | os.chdir(build_dir)
438 |
439 | print('Using config: {}'.format(args.config))
440 | print('Using cpu: {}'.format(args.cpu))
441 | if args.compiler:
442 | print('Using compiler: {}'.format(args.compiler))
443 | print('Using C++-{}'.format(args.cpp_version))
444 | print('Using {} threads'.format(args.num_threads))
445 |
446 | # Make sure 'make' runs with all available cores
447 | os.environ['MAKEFLAGS'] = '-j{}'.format(args.num_threads)
448 |
449 | do_generate_solution(build_dir, cmake_script_dir, args)
450 |
451 | if args.build:
452 | do_build(args)
453 |
454 | if args.unit_test:
455 | do_tests(build_dir, args)
456 |
457 | sys.exit(0)
458 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.organization=nfrechette-github
2 |
3 | sonar.projectKey=nfrechette_sjson-cpp
4 | sonar.projectName=sjson-cpp
5 | sonar.projectVersion=0.9.99
6 |
7 | sonar.sources=includes,tests/sources,tests/main_generic
8 |
9 | sonar.cfamily.build-wrapper-output=bw_output
10 | sonar.cfamily.threads=2
11 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 | project(sjson-cpp_unit_tests_root NONE)
3 |
4 | if(PLATFORM_ANDROID)
5 | add_subdirectory("${PROJECT_SOURCE_DIR}/main_android")
6 | elseif(PLATFORM_IOS)
7 | add_subdirectory("${PROJECT_SOURCE_DIR}/main_ios")
8 | elseif(PLATFORM_EMSCRIPTEN)
9 | add_subdirectory("${PROJECT_SOURCE_DIR}/main_emscripten")
10 | else()
11 | add_subdirectory("${PROJECT_SOURCE_DIR}/main_generic")
12 | add_subdirectory("${PROJECT_SOURCE_DIR}/validate_includes")
13 | endif()
14 |
--------------------------------------------------------------------------------
/tests/main_android/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 | project(sjson-cpp_unit_tests_gradle_shim NONE)
3 |
4 | # Set our project root since our gradle files used to build live in the binary output directory
5 | # but the actual source files live in the source/current directory.
6 | set(SJSON_PROJECT_ROOT ${CMAKE_CURRENT_BINARY_DIR}/app)
7 | file(RELATIVE_PATH SJSON_PROJECT_ROOT ${SJSON_PROJECT_ROOT} ${PROJECT_SOURCE_DIR}/app)
8 |
9 | # Configure gradle for our build configuration
10 | configure_file(app/build.gradle.in app/build.gradle @ONLY)
11 |
12 | # Copy gradle related files
13 | file(COPY build.gradle gradle.properties settings.gradle gradle DESTINATION .)
14 |
15 | add_custom_target(${PROJECT_NAME} ALL
16 | COMMAND "${PROJECT_SOURCE_DIR}/gradlew.bat"
17 | # Decide whether we should build Debug or Release
18 | $<$:assembleDebug>
19 | $<$:assembleRelease>)
20 |
--------------------------------------------------------------------------------
/tests/main_android/app/build.gradle.in:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | ndkVersion "20.1.5948944"
5 | compileSdkVersion 28
6 | defaultConfig {
7 | applicationId "com.sjson.unit_tests"
8 | minSdkVersion 24
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | externalNativeBuild {
14 | cmake {
15 | arguments '-DCMAKE_CXX_STANDARD=@CMAKE_CXX_STANDARD@'
16 | }
17 | }
18 | ndk {
19 | abiFilters '@CPU_INSTRUCTION_SET@'
20 | }
21 |
22 | }
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
27 | debuggable = true
28 | signingConfig signingConfigs.debug
29 | externalNativeBuild {
30 | cmake {
31 | // Because we want to debug 'release' builds, the 'debuggable' property above
32 | // forces the build configuration to 'Debug' which disables optimizations.
33 | // Force a release configutation anyway.
34 | arguments '-DCMAKE_BUILD_TYPE=Release'
35 | }
36 | }
37 | }
38 | }
39 | externalNativeBuild {
40 | cmake {
41 | path '@SJSON_PROJECT_ROOT@/src/main/cpp/CMakeLists.txt'
42 | }
43 | }
44 | sourceSets {
45 | main {
46 | manifest.srcFile '@SJSON_PROJECT_ROOT@/src/main/AndroidManifest.xml'
47 | java.srcDirs = ['@SJSON_PROJECT_ROOT@/src/main/java']
48 | res.srcDirs = ['@SJSON_PROJECT_ROOT@/src/main/res']
49 | }
50 | }
51 | }
52 |
53 | dependencies {
54 | implementation fileTree(dir: 'libs', include: ['*.jar'])
55 | implementation 'androidx.appcompat:appcompat:1.0.2'
56 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
57 | }
58 |
--------------------------------------------------------------------------------
/tests/main_android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/tests/main_android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tests/main_android/app/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.2)
2 | project(sjson-cpp_unit_tests CXX)
3 |
4 | # Project root is \tests\main_android
5 | set(PROJECT_ROOT_DIR "${PROJECT_SOURCE_DIR}/../../../..")
6 |
7 | include_directories("${PROJECT_ROOT_DIR}/../../includes")
8 | include_directories("${PROJECT_ROOT_DIR}/../../external/catch2/single_include")
9 | include_directories("${PROJECT_ROOT_DIR}/../sources")
10 |
11 | # Grab all of our test source files
12 | file(GLOB_RECURSE ALL_TEST_SOURCE_FILES LIST_DIRECTORIES false
13 | ${PROJECT_ROOT_DIR}/../sources/*.h
14 | ${PROJECT_ROOT_DIR}/../sources/*.cpp)
15 |
16 | # Grab all of our main source files
17 | file(GLOB_RECURSE ALL_MAIN_SOURCE_FILES LIST_DIRECTORIES false
18 | ${PROJECT_SOURCE_DIR}/*.cpp)
19 |
20 | add_library(${PROJECT_NAME} SHARED ${ALL_TEST_SOURCE_FILES} ${ALL_MAIN_SOURCE_FILES})
21 |
22 | # Enable exceptions
23 | target_compile_options(${PROJECT_NAME} PRIVATE -fexceptions)
24 |
25 | # Enable debug symbols
26 | target_compile_options(${PROJECT_NAME} PRIVATE -g)
27 |
28 | # Throw on failure to allow us to catch them and recover
29 | add_definitions(-DSJSON_CPP_ON_ASSERT_THROW)
30 |
31 | target_include_directories(${PROJECT_NAME} PUBLIC jni)
32 |
33 | target_link_libraries(${PROJECT_NAME} m log)
34 |
--------------------------------------------------------------------------------
/tests/main_android/app/src/main/cpp/main.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #define CATCH_CONFIG_RUNNER
26 | #include "catch2.impl.h"
27 |
28 | #include
29 |
30 | extern "C" jint Java_com_sjson_unit_1tests_MainActivity_getNumUnitTestCases(JNIEnv* env, jobject caller)
31 | {
32 | return Catch::getRegistryHub().getTestCaseRegistry().getAllTests().size();
33 | }
34 |
35 | extern "C" jint Java_com_sjson_unit_1tests_MainActivity_runUnitTests(JNIEnv* env, jobject caller)
36 | {
37 | int result = Catch::Session().run();
38 |
39 | return (result < 0xff ? result : 0xff);
40 | }
41 |
--------------------------------------------------------------------------------
/tests/main_android/app/src/main/java/com/sjson/unit_tests/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.sjson.unit_tests;
2 |
3 | import android.app.Activity;
4 | import android.widget.TextView;
5 | import android.os.Bundle;
6 |
7 | public class MainActivity extends Activity {
8 | static {
9 | System.loadLibrary("sjson-cpp_unit_tests");
10 | }
11 |
12 | @Override
13 | public void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 |
16 | TextView resultTextView = new TextView(this);
17 |
18 | int numUnitTestCases = getNumUnitTestCases();
19 | int numFailed = runUnitTests();
20 |
21 | if (numFailed == 0)
22 | resultTextView.setText("All " + numUnitTestCases + " test cases ran successfully!");
23 | else
24 | resultTextView.setText(numFailed + " test cases failed!");
25 |
26 | setContentView(resultTextView);
27 | }
28 |
29 | public native int getNumUnitTestCases();
30 | public native int runUnitTests();
31 | }
32 |
--------------------------------------------------------------------------------
/tests/main_android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | sjson-cpp Unit Tests
4 |
5 |
--------------------------------------------------------------------------------
/tests/main_android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.3'
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | allprojects {
17 | repositories {
18 | google()
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/tests/main_android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 |
21 | # Run tasks in parallel
22 | org.gradle.parallel=true
23 |
--------------------------------------------------------------------------------
/tests/main_android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nfrechette/sjson-cpp/c9490dd1ccd09bc14ee3f3e1517e8171856abd13/tests/main_android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/tests/main_android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 27 21:02:15 EDT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
7 |
--------------------------------------------------------------------------------
/tests/main_android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/tests/main_android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/tests/main_android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name='sjson-cpp Unit Tests'
3 |
--------------------------------------------------------------------------------
/tests/main_emscripten/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 | project(sjson-cpp_unit_tests CXX)
3 |
4 | include_directories("${PROJECT_SOURCE_DIR}/../../includes")
5 | include_directories("${PROJECT_SOURCE_DIR}/../../external/catch2/single_include")
6 | include_directories("${PROJECT_SOURCE_DIR}/../sources")
7 |
8 | # Grab all of our test source files
9 | file(GLOB_RECURSE ALL_TEST_SOURCE_FILES LIST_DIRECTORIES false
10 | ${PROJECT_SOURCE_DIR}/../sources/*.h
11 | ${PROJECT_SOURCE_DIR}/../sources/*.cpp)
12 |
13 | # Grab all of our main source files
14 | file(GLOB_RECURSE ALL_MAIN_SOURCE_FILES LIST_DIRECTORIES false
15 | ${PROJECT_SOURCE_DIR}/*.cpp)
16 |
17 | add_executable(${PROJECT_NAME} ${ALL_TEST_SOURCE_FILES} ${ALL_MAIN_SOURCE_FILES})
18 |
19 | # Throw on failure to allow us to catch them and recover
20 | add_definitions(-DSJSON_CPP_ON_ASSERT_THROW)
21 |
22 | target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra) # Enable all warnings
23 | target_compile_options(${PROJECT_NAME} PRIVATE -Wshadow) # Enable shadowing warnings
24 | target_compile_options(${PROJECT_NAME} PRIVATE -Werror) # Treat warnings as errors
25 |
26 | # Exceptions are not enabled by default, enable them
27 | target_compile_options(${PROJECT_NAME} PRIVATE -fexceptions)
28 | target_link_libraries(${PROJECT_NAME} PRIVATE "-s DISABLE_EXCEPTION_CATCHING=0")
29 |
30 | target_link_libraries(${PROJECT_NAME} PRIVATE "-s NODERAWFS=1") # Enable the raw node file system
31 | target_link_libraries(${PROJECT_NAME} PRIVATE -lnodefs.js) # Link the node file system
32 |
33 | target_link_libraries(${PROJECT_NAME} PRIVATE "-s ENVIRONMENT=node") # Force the environment to node
34 |
35 | target_link_libraries(${PROJECT_NAME} PRIVATE "-s ALLOW_MEMORY_GROWTH=1") # Allow dynamic memory allocation
36 |
37 | # Setup Catch2 so we can find and execute the unit tests with CTest
38 | set(OptionalCatchTestLauncher node)
39 | list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../external/catch2/contrib")
40 | include(CTest)
41 | include(ParseAndAddCatchTests)
42 | ParseAndAddCatchTests(${PROJECT_NAME})
43 |
44 | install(FILES
45 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.js
46 | ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.wasm
47 | DESTINATION bin)
48 |
--------------------------------------------------------------------------------
/tests/main_emscripten/main.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2020 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #define CATCH_CONFIG_RUNNER
26 | #include "catch2.impl.h"
27 |
28 | int main(int argc, char* argv[])
29 | {
30 | int result = Catch::Session().run(argc, argv);
31 | return (result < 0xff ? result : 0xff);
32 | }
33 |
--------------------------------------------------------------------------------
/tests/main_generic/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 | project(sjson-cpp_unit_tests CXX)
3 |
4 | include_directories("${PROJECT_SOURCE_DIR}/../../includes")
5 | include_directories("${PROJECT_SOURCE_DIR}/../../external/catch2/single_include")
6 | include_directories("${PROJECT_SOURCE_DIR}/../sources")
7 |
8 | # Grab all of our test source files
9 | file(GLOB_RECURSE ALL_TEST_SOURCE_FILES LIST_DIRECTORIES false
10 | ${PROJECT_SOURCE_DIR}/../sources/*.h
11 | ${PROJECT_SOURCE_DIR}/../sources/*.cpp)
12 |
13 | create_source_groups("${ALL_TEST_SOURCE_FILES}" ${PROJECT_SOURCE_DIR}/..)
14 |
15 | # Grab all of our main source files
16 | file(GLOB_RECURSE ALL_MAIN_SOURCE_FILES LIST_DIRECTORIES false
17 | ${PROJECT_SOURCE_DIR}/*.cpp)
18 |
19 | create_source_groups("${ALL_MAIN_SOURCE_FILES}" ${PROJECT_SOURCE_DIR})
20 |
21 | add_executable(${PROJECT_NAME} ${ALL_TEST_SOURCE_FILES} ${ALL_MAIN_SOURCE_FILES})
22 |
23 | list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/../../external/catch2/contrib")
24 | include(CTest)
25 | include(Catch)
26 | catch_discover_tests(${PROJECT_NAME})
27 |
28 | setup_default_compiler_flags(${PROJECT_NAME})
29 |
30 | if(MSVC)
31 | if(CPU_INSTRUCTION_SET MATCHES "arm64")
32 | # Exceptions are not enabled by default for ARM targets, enable them
33 | target_compile_options(${PROJECT_NAME} PRIVATE /EHsc)
34 | endif()
35 |
36 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
37 | target_compile_options(${PROJECT_NAME} PRIVATE -Wno-float-equal) # Float comparison
38 | endif()
39 | endif()
40 |
41 | # Throw on failure to allow us to catch them and recover
42 | add_definitions(-DSJSON_CPP_ON_ASSERT_THROW)
43 |
44 | install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)
45 |
--------------------------------------------------------------------------------
/tests/main_generic/main.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #define CATCH_CONFIG_RUNNER
26 | #include "catch2.impl.h"
27 |
28 | #ifdef _WIN32
29 | #include
30 | #endif
31 |
32 | int main(int argc, char* argv[])
33 | {
34 | int result = Catch::Session().run(argc, argv);
35 |
36 | #ifdef _WIN32
37 | if (IsDebuggerPresent())
38 | {
39 | printf("Press any key to continue...\n");
40 | while (_kbhit() == 0);
41 | }
42 | #endif
43 |
44 | return (result < 0xff ? result : 0xff);
45 | }
46 |
--------------------------------------------------------------------------------
/tests/main_ios/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 | project(sjson-cpp_unit_tests)
3 |
4 | # iOS cmake toolchain does not support CMAKE_CXX_STANDARD
5 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CMAKE_CXX_STANDARD}")
6 |
7 | # Force enable debug symbols
8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
9 |
10 | # Enable optimizations in Release
11 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
12 |
13 | set(MACOSX_BUNDLE_EXECUTABLE_NAME ${PROJECT_NAME})
14 | set(MACOSX_BUNDLE_INFO_STRING "com.sjson.cpp.unit-tests")
15 | set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.sjson.cpp.unit-tests")
16 | set(MACOSX_BUNDLE_BUNDLE_NAME "sjson-cpp-unit-tests")
17 |
18 | include_directories("${PROJECT_SOURCE_DIR}/../../includes")
19 | include_directories("${PROJECT_SOURCE_DIR}/../../external/catch2/single_include")
20 | include_directories("${PROJECT_SOURCE_DIR}/../sources")
21 |
22 | # Grab all of our test source files
23 | file(GLOB_RECURSE ALL_TEST_SOURCE_FILES LIST_DIRECTORIES false
24 | ${PROJECT_SOURCE_DIR}/../sources/*.h
25 | ${PROJECT_SOURCE_DIR}/../sources/*.cpp)
26 |
27 | create_source_groups("${ALL_TEST_SOURCE_FILES}" ${PROJECT_SOURCE_DIR}/..)
28 |
29 | # Grab all of our main source files
30 | file(GLOB_RECURSE ALL_MAIN_SOURCE_FILES LIST_DIRECTORIES false
31 | ${PROJECT_SOURCE_DIR}/*.cpp)
32 |
33 | create_source_groups("${ALL_MAIN_SOURCE_FILES}" ${PROJECT_SOURCE_DIR})
34 |
35 | add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${ALL_TEST_SOURCE_FILES} ${ALL_MAIN_SOURCE_FILES})
36 |
37 | # Throw on failure to allow us to catch them and recover
38 | add_definitions(-DSJSON_CPP_ON_ASSERT_THROW)
39 |
40 | # Set XCode properties
41 | set_property(TARGET ${PROJECT_NAME} PROPERTY XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "com.sjson.cpp.unit-tests")
42 |
--------------------------------------------------------------------------------
/tests/main_ios/main.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #define CATCH_CONFIG_RUNNER
26 | #include "catch2.impl.h"
27 |
28 | int main(int argc, char* argv[])
29 | {
30 | int result = Catch::Session().run(argc, argv);
31 |
32 | return (result < 0xff ? result : 0xff);
33 | }
34 |
--------------------------------------------------------------------------------
/tests/sources/catch2.impl.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2023 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | // We disable various informational warnings with using /Wall with MSVC caused by Catch2
26 |
27 | #if defined(_MSC_VER) && !defined(__clang__)
28 | #pragma warning(push)
29 | #pragma warning(disable : 4365) // Signed/unsigned mismatch
30 | #pragma warning(disable : 4388) // Signed/unsigned comparison
31 | #pragma warning(disable : 4583) // Destructor is not implicitly called
32 | #pragma warning(disable : 4623) // Default constructor implicitly deleted
33 | #pragma warning(disable : 4625) // Copy constructor implicitly deleted
34 | #pragma warning(disable : 4626) // Copy assignment operator implicitly deleted
35 | #pragma warning(disable : 4868) // May not enforce left to right order in initializer
36 | #pragma warning(disable : 5026) // Move constructor implicitly deleted
37 | #pragma warning(disable : 5027) // Move assignment operator implicitly deleted
38 | #pragma warning(disable : 5039) // Pointer to potentially throwing function passed to extern C
39 | #pragma warning(disable : 5204) // Class has virtual functions but no virtual destructor
40 | #pragma warning(disable : 5219) // Implicit conversion, possible loss of data
41 | #pragma warning(disable : 5267) // Implicit copy constructor deprecated due to user destructor
42 | #endif
43 |
44 | #include
45 |
46 | #if defined(_MSC_VER) && !defined(__clang__)
47 | #pragma warning(pop)
48 | #endif
49 |
--------------------------------------------------------------------------------
/tests/sources/test_header_fwd.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2022 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #include
26 |
--------------------------------------------------------------------------------
/tests/sources/test_parser.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #include "catch2.impl.h"
26 |
27 | #include
28 |
29 | using namespace sjson;
30 |
31 | static Parser parser_from_c_str(const char* c_str)
32 | {
33 | return Parser(c_str, c_str != nullptr ? std::strlen(c_str) : 0);
34 | }
35 |
36 | TEST_CASE("Parser Misc", "[parser]")
37 | {
38 | {
39 | Parser parser = parser_from_c_str("");
40 | CHECK(parser.eof());
41 | CHECK(parser.is_valid());
42 | }
43 |
44 | {
45 | Parser parser = parser_from_c_str("");
46 | CHECK(parser.remainder_is_comments_and_whitespace());
47 | CHECK(parser.eof());
48 | CHECK(parser.is_valid());
49 | }
50 |
51 | {
52 | Parser parser = parser_from_c_str(" ");
53 | CHECK(parser.remainder_is_comments_and_whitespace());
54 | CHECK(parser.eof());
55 | CHECK(parser.is_valid());
56 | }
57 |
58 | {
59 | Parser parser = parser_from_c_str("// lol \\n ");
60 | CHECK(parser.remainder_is_comments_and_whitespace());
61 | CHECK(parser.eof());
62 | CHECK(parser.is_valid());
63 | }
64 |
65 | {
66 | Parser parser = parser_from_c_str("\"key-one\" = true");
67 | bool value = false;
68 | CHECK(parser.read("key-one", value));
69 | CHECK(value == true);
70 | CHECK(parser.eof());
71 | CHECK(parser.is_valid());
72 | }
73 |
74 | {
75 | Parser parser = parser_from_c_str("key = /* bar */ true");
76 | bool value = false;
77 | CHECK(parser.read("key", value));
78 | CHECK(value == true);
79 | CHECK(parser.eof());
80 | CHECK(parser.is_valid());
81 | }
82 |
83 | {
84 | Parser parser = parser_from_c_str("key = /* bar * true");
85 | bool value = false;
86 | CHECK_FALSE(parser.read("key", value));
87 | CHECK_FALSE(parser.is_valid());
88 | }
89 |
90 | {
91 | Parser parser = parser_from_c_str("key = // bar \ntrue");
92 | bool value = false;
93 | CHECK(parser.read("key", value));
94 | CHECK(value == true);
95 | CHECK(parser.eof());
96 | CHECK(parser.is_valid());
97 | }
98 |
99 | {
100 | Parser parser = parser_from_c_str("key /* bar */ = true");
101 | bool value = false;
102 | CHECK(parser.read("key", value));
103 | CHECK(value == true);
104 | CHECK(parser.eof());
105 | CHECK(parser.is_valid());
106 | }
107 |
108 | {
109 | Parser parser = parser_from_c_str("/* bar */ key = true");
110 | bool value = false;
111 | CHECK(parser.read("key", value));
112 | CHECK(value == true);
113 | CHECK(parser.eof());
114 | CHECK(parser.is_valid());
115 | }
116 | }
117 |
118 | TEST_CASE("Parser Bool Reading", "[parser]")
119 | {
120 | {
121 | Parser parser = parser_from_c_str("key = true");
122 | bool value = false;
123 | CHECK(parser.read("key", value));
124 | CHECK(value == true);
125 | CHECK(parser.eof());
126 | CHECK(parser.is_valid());
127 | }
128 |
129 | {
130 | Parser parser = parser_from_c_str("key = false");
131 | bool value = true;
132 | CHECK(parser.read("key", value));
133 | CHECK(value == false);
134 | CHECK(parser.eof());
135 | CHECK(parser.is_valid());
136 | }
137 |
138 | {
139 | Parser parser = parser_from_c_str("bad_key = 0");
140 | bool value = true;
141 | CHECK_FALSE(parser.try_read("key", value, false));
142 | CHECK(value == false);
143 | CHECK_FALSE(parser.eof());
144 | CHECK(parser.is_valid());
145 | }
146 |
147 | {
148 | Parser parser = parser_from_c_str("key = true");
149 | bool value = false;
150 | CHECK(parser.try_read("key", value, false));
151 | CHECK(value == true);
152 | CHECK(parser.eof());
153 | CHECK(parser.is_valid());
154 | }
155 | }
156 |
157 | TEST_CASE("Parser String Reading", "[parser]")
158 | {
159 | {
160 | Parser parser = parser_from_c_str("key = \"Quoted string\"");
161 | StringView value;
162 | CHECK(parser.read("key", value));
163 | CHECK(value == "Quoted string");
164 | CHECK(parser.eof());
165 | CHECK(parser.is_valid());
166 | }
167 |
168 | {
169 | // Note: Escaped quotes \" are left escaped within the StringView because we do not allocate memory
170 | Parser parser = parser_from_c_str("key = \"Quoted \\\" string\"");
171 | StringView value;
172 | CHECK(parser.read("key", value));
173 | CHECK(value == "Quoted \\\" string");
174 | CHECK(parser.eof());
175 | CHECK(parser.is_valid());
176 | }
177 |
178 | {
179 | Parser parser = parser_from_c_str("key = \"New\\nline\"");
180 | StringView value;
181 | CHECK(parser.read("key", value));
182 | CHECK(value == "New\\nline");
183 | CHECK(parser.eof());
184 | CHECK(parser.is_valid());
185 | }
186 |
187 | {
188 | Parser parser = parser_from_c_str("key = \"Tab\\tulator\"");
189 | StringView value;
190 | CHECK(parser.read("key", value));
191 | CHECK(value == "Tab\\tulator");
192 | CHECK(parser.eof());
193 | CHECK(parser.is_valid());
194 | }
195 |
196 | {
197 | Parser parser = parser_from_c_str("key = \"Tab\\tulator\"");
198 | StringView value;
199 | CHECK(parser.read("key", value));
200 | CHECK(value == "Tab\\tulator");
201 | CHECK(parser.eof());
202 | CHECK(parser.is_valid());
203 | }
204 |
205 | {
206 | Parser parser = parser_from_c_str("bad_key = 0");
207 | StringView value;
208 | CHECK_FALSE(parser.try_read("key", value, "default"));
209 | CHECK(value == "default");
210 | CHECK_FALSE(parser.eof());
211 | CHECK(parser.is_valid());
212 | }
213 |
214 | {
215 | Parser parser = parser_from_c_str("key = \"good\"");
216 | StringView value;
217 | CHECK(parser.try_read("key", value, "default"));
218 | CHECK(value == "good");
219 | CHECK(parser.eof());
220 | CHECK(parser.is_valid());
221 | }
222 |
223 | {
224 | Parser parser = parser_from_c_str("key = \"bad");
225 | StringView value;
226 | CHECK_FALSE(parser.read("key", value));
227 | CHECK_FALSE(parser.is_valid());
228 | }
229 |
230 | {
231 | Parser parser = parser_from_c_str("key = bad");
232 | StringView value;
233 | CHECK_FALSE(parser.read("key", value));
234 | CHECK_FALSE(parser.is_valid());
235 | }
236 | }
237 |
238 | TEST_CASE("Parser Number Reading", "[parser]")
239 | {
240 | // Number reading
241 | {
242 | Parser parser = parser_from_c_str("key = 123.456789");
243 | double value = 0.0;
244 | CHECK(parser.read("key", value));
245 | CHECK(value == 123.456789);
246 | CHECK(parser.eof());
247 | CHECK(parser.is_valid());
248 | }
249 |
250 | {
251 | Parser parser = parser_from_c_str("key = \"nan\"");
252 | double value = 0.0;
253 | CHECK(parser.read("key", value));
254 | CHECK(std::isnan(value));
255 | CHECK(parser.eof());
256 | CHECK(parser.is_valid());
257 | }
258 |
259 | {
260 | Parser parser = parser_from_c_str("key = \"inf\"");
261 | double value = 0.0;
262 | CHECK(parser.read("key", value));
263 | CHECK(std::isinf(value));
264 | CHECK(value > 0.0);
265 | CHECK(parser.eof());
266 | CHECK(parser.is_valid());
267 | }
268 |
269 | {
270 | Parser parser = parser_from_c_str("key = \"-inf\"");
271 | double value = 0.0;
272 | CHECK(parser.read("key", value));
273 | CHECK(std::isinf(value));
274 | CHECK(value < 0.0);
275 | CHECK(parser.eof());
276 | CHECK(parser.is_valid());
277 | }
278 |
279 | {
280 | Parser parser = parser_from_c_str("key = 123.456789");
281 | float value = 0.0F;
282 | CHECK(parser.read("key", value));
283 | CHECK(value == 123.456789F);
284 | CHECK(parser.eof());
285 | CHECK(parser.is_valid());
286 | }
287 |
288 | {
289 | Parser parser = parser_from_c_str("key = \"nan\"");
290 | float value = 0.0F;
291 | CHECK(parser.read("key", value));
292 | CHECK(std::isnan(value));
293 | CHECK(parser.eof());
294 | CHECK(parser.is_valid());
295 | }
296 |
297 | {
298 | Parser parser = parser_from_c_str("key = \"inf\"");
299 | float value = 0.0F;
300 | CHECK(parser.read("key", value));
301 | CHECK(std::isinf(value));
302 | CHECK(value > 0.0F);
303 | CHECK(parser.eof());
304 | CHECK(parser.is_valid());
305 | }
306 |
307 | {
308 | Parser parser = parser_from_c_str("key = \"-inf\"");
309 | float value = 0.0F;
310 | CHECK(parser.read("key", value));
311 | CHECK(std::isinf(value));
312 | CHECK(value < 0.0F);
313 | CHECK(parser.eof());
314 | CHECK(parser.is_valid());
315 | }
316 |
317 | {
318 | Parser parser = parser_from_c_str("key = -123");
319 | int8_t value = 0;
320 | CHECK(parser.read("key", value));
321 | CHECK(value == -123);
322 | CHECK(parser.eof());
323 | CHECK(parser.is_valid());
324 | }
325 |
326 | {
327 | Parser parser = parser_from_c_str("key = 123");
328 | uint8_t value = 0;
329 | CHECK(parser.read("key", value));
330 | CHECK(value == 123);
331 | CHECK(parser.eof());
332 | CHECK(parser.is_valid());
333 | }
334 |
335 | {
336 | Parser parser = parser_from_c_str("key = -1234");
337 | int16_t value = 0;
338 | CHECK(parser.read("key", value));
339 | CHECK(value == -1234);
340 | CHECK(parser.eof());
341 | CHECK(parser.is_valid());
342 | }
343 |
344 | {
345 | Parser parser = parser_from_c_str("key = 1234");
346 | uint16_t value = 0;
347 | CHECK(parser.read("key", value));
348 | CHECK(value == 1234);
349 | CHECK(parser.eof());
350 | CHECK(parser.is_valid());
351 | }
352 |
353 | {
354 | Parser parser = parser_from_c_str("key = -123456");
355 | int32_t value = 0;
356 | CHECK(parser.read("key", value));
357 | CHECK(value == -123456);
358 | CHECK(parser.eof());
359 | CHECK(parser.is_valid());
360 | }
361 |
362 | {
363 | Parser parser = parser_from_c_str("key = 123456");
364 | uint32_t value = 0;
365 | CHECK(parser.read("key", value));
366 | CHECK(value == 123456);
367 | CHECK(parser.eof());
368 | CHECK(parser.is_valid());
369 | }
370 |
371 | {
372 | Parser parser = parser_from_c_str("key = -1234567890123456");
373 | int64_t value = 0;
374 | CHECK(parser.read("key", value));
375 | CHECK(value == -1234567890123456LL);
376 | CHECK(parser.eof());
377 | CHECK(parser.is_valid());
378 | }
379 |
380 | {
381 | Parser parser = parser_from_c_str("key = 1234567890123456");
382 | uint64_t value = 0;
383 | CHECK(parser.read("key", value));
384 | CHECK(value == 1234567890123456ULL);
385 | CHECK(parser.eof());
386 | CHECK(parser.is_valid());
387 | }
388 |
389 | // Number try reading
390 |
391 | {
392 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
393 | double value = 0.0;
394 | CHECK_FALSE(parser.try_read("key", value, 1.0));
395 | CHECK(value == 1.0);
396 | CHECK_FALSE(parser.eof());
397 | CHECK(parser.is_valid());
398 | }
399 |
400 | {
401 | Parser parser = parser_from_c_str("key = 2.0");
402 | double value = 0.0;
403 | CHECK(parser.try_read("key", value, 1.0));
404 | CHECK(value == 2.0);
405 | CHECK(parser.eof());
406 | CHECK(parser.is_valid());
407 | }
408 |
409 | {
410 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
411 | float value = 0.0F;
412 | CHECK_FALSE(parser.try_read("key", value, 1.0F));
413 | CHECK(value == 1.0F);
414 | CHECK_FALSE(parser.eof());
415 | CHECK(parser.is_valid());
416 | }
417 |
418 | {
419 | Parser parser = parser_from_c_str("key = 2.0");
420 | float value = 0.0F;
421 | CHECK(parser.try_read("key", value, 1.0F));
422 | CHECK(value == 2.0F);
423 | CHECK(parser.eof());
424 | CHECK(parser.is_valid());
425 | }
426 |
427 | {
428 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
429 | int8_t value = 0;
430 | CHECK_FALSE(parser.try_read("key", value, 1));
431 | CHECK(value == 1);
432 | CHECK_FALSE(parser.eof());
433 | CHECK(parser.is_valid());
434 | }
435 |
436 | {
437 | Parser parser = parser_from_c_str("key = -123");
438 | int8_t value = 0;
439 | CHECK(parser.try_read("key", value, 1));
440 | CHECK(value == -123);
441 | CHECK(parser.eof());
442 | CHECK(parser.is_valid());
443 | }
444 |
445 | {
446 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
447 | uint8_t value = 0;
448 | CHECK_FALSE(parser.try_read("key", value, 1));
449 | CHECK(value == 1);
450 | CHECK_FALSE(parser.eof());
451 | CHECK(parser.is_valid());
452 | }
453 |
454 | {
455 | Parser parser = parser_from_c_str("key = 123");
456 | uint8_t value = 0;
457 | CHECK(parser.try_read("key", value, 1));
458 | CHECK(value == 123);
459 | CHECK(parser.eof());
460 | CHECK(parser.is_valid());
461 | }
462 |
463 | {
464 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
465 | int16_t value = 0;
466 | CHECK_FALSE(parser.try_read("key", value, 1));
467 | CHECK(value == 1);
468 | CHECK_FALSE(parser.eof());
469 | CHECK(parser.is_valid());
470 | }
471 |
472 | {
473 | Parser parser = parser_from_c_str("key = -1234");
474 | int16_t value = 0;
475 | CHECK(parser.try_read("key", value, 1));
476 | CHECK(value == -1234);
477 | CHECK(parser.eof());
478 | CHECK(parser.is_valid());
479 | }
480 |
481 | {
482 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
483 | uint16_t value = 0;
484 | CHECK_FALSE(parser.try_read("key", value, 1));
485 | CHECK(value == 1);
486 | CHECK_FALSE(parser.eof());
487 | CHECK(parser.is_valid());
488 | }
489 |
490 | {
491 | Parser parser = parser_from_c_str("key = 1234");
492 | uint16_t value = 0;
493 | CHECK(parser.try_read("key", value, 1));
494 | CHECK(value == 1234);
495 | CHECK(parser.eof());
496 | CHECK(parser.is_valid());
497 | }
498 |
499 | {
500 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
501 | int32_t value = 0;
502 | CHECK_FALSE(parser.try_read("key", value, 1));
503 | CHECK(value == 1);
504 | CHECK_FALSE(parser.eof());
505 | CHECK(parser.is_valid());
506 | }
507 |
508 | {
509 | Parser parser = parser_from_c_str("key = -123456");
510 | int32_t value = 0;
511 | CHECK(parser.try_read("key", value, 1));
512 | CHECK(value == -123456);
513 | CHECK(parser.eof());
514 | CHECK(parser.is_valid());
515 | }
516 |
517 | {
518 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
519 | uint32_t value = 0;
520 | CHECK_FALSE(parser.try_read("key", value, 1));
521 | CHECK(value == 1);
522 | CHECK_FALSE(parser.eof());
523 | CHECK(parser.is_valid());
524 | }
525 |
526 | {
527 | Parser parser = parser_from_c_str("key = 123456");
528 | uint32_t value = 0;
529 | CHECK(parser.try_read("key", value, 1));
530 | CHECK(value == 123456);
531 | CHECK(parser.eof());
532 | CHECK(parser.is_valid());
533 | }
534 |
535 | {
536 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
537 | int64_t value = 0;
538 | CHECK_FALSE(parser.try_read("key", value, 1));
539 | CHECK(value == 1);
540 | CHECK_FALSE(parser.eof());
541 | CHECK(parser.is_valid());
542 | }
543 |
544 | {
545 | Parser parser = parser_from_c_str("key = -1234567890123456");
546 | int64_t value = 0;
547 | CHECK(parser.try_read("key", value, 1));
548 | CHECK(value == -1234567890123456LL);
549 | CHECK(parser.eof());
550 | CHECK(parser.is_valid());
551 | }
552 |
553 | {
554 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
555 | uint64_t value = 0;
556 | CHECK_FALSE(parser.try_read("key", value, 1));
557 | CHECK(value == 1);
558 | CHECK_FALSE(parser.eof());
559 | CHECK(parser.is_valid());
560 | }
561 |
562 | {
563 | Parser parser = parser_from_c_str("key = 1234567890123456");
564 | uint64_t value = 0;
565 | CHECK(parser.try_read("key", value, 1));
566 | CHECK(value == 1234567890123456ULL);
567 | CHECK(parser.eof());
568 | CHECK(parser.is_valid());
569 | }
570 | }
571 |
572 | TEST_CASE("Parser Array Reading", "[parser]")
573 | {
574 | {
575 | Parser parser = parser_from_c_str("key = [ 123.456789, 456.789, 151.091 ]");
576 | double value[3] = { 0.0, 0.0, 0.0 };
577 | CHECK(parser.read("key", value, 3));
578 | CHECK(value[0] == 123.456789);
579 | CHECK(value[1] == 456.789);
580 | CHECK(value[2] == 151.091);
581 | CHECK(parser.eof());
582 | CHECK(parser.is_valid());
583 | }
584 |
585 | {
586 | Parser parser = parser_from_c_str("key = [ \"123.456789\", \"456.789\", \"151.091\" ]");
587 | StringView value[3];
588 | CHECK(parser.read("key", value, 3));
589 | CHECK(value[0] == "123.456789");
590 | CHECK(value[1] == "456.789");
591 | CHECK(value[2] == "151.091");
592 | CHECK(parser.eof());
593 | CHECK(parser.is_valid());
594 | }
595 |
596 | {
597 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
598 | double value[3] = { 0.0, 0.0, 0.0 };
599 | CHECK_FALSE(parser.try_read("key", value, 3, 1.0));
600 | CHECK(value[0] == 1.0);
601 | CHECK(value[1] == 1.0);
602 | CHECK(value[2] == 1.0);
603 | CHECK_FALSE(parser.eof());
604 | CHECK(parser.is_valid());
605 | }
606 |
607 | {
608 | Parser parser = parser_from_c_str("key = [ 123.456789, 456.789, 151.091 ]");
609 | double value[3] = { 0.0, 0.0, 0.0 };
610 | CHECK(parser.try_read("key", value, 3, 1.0));
611 | CHECK(value[0] == 123.456789);
612 | CHECK(value[1] == 456.789);
613 | CHECK(value[2] == 151.091);
614 | CHECK(parser.eof());
615 | CHECK(parser.is_valid());
616 | }
617 |
618 | {
619 | Parser parser = parser_from_c_str("bad_key = \"bad\"");
620 | StringView value[3];
621 | CHECK_FALSE(parser.try_read("key", value, 3, "default"));
622 | CHECK(value[0] == "default");
623 | CHECK(value[1] == "default");
624 | CHECK(value[2] == "default");
625 | CHECK_FALSE(parser.eof());
626 | CHECK(parser.is_valid());
627 | }
628 |
629 | {
630 | Parser parser = parser_from_c_str("key = [ \"123.456789\", \"456.789\", \"151.091\" ]");
631 | StringView value[3];
632 | CHECK(parser.try_read("key", value, 3, "default"));
633 | CHECK(value[0] == "123.456789");
634 | CHECK(value[1] == "456.789");
635 | CHECK(value[2] == "151.091");
636 | CHECK(parser.eof());
637 | CHECK(parser.is_valid());
638 | }
639 |
640 | #if 0
641 | {
642 | Parser parser = parser_from_c_str("key = [ 123.456789, \"456.789\", false, [ 1.0, true ], { key0 = 1.0, key1 = false } ]");
643 |
644 | CHECK(parser.array_begins("key"));
645 | // TODO
646 | CHECK(parser.array_ends());
647 | CHECK(parser.eof());
648 | CHECK(parser.is_valid());
649 | }
650 | #endif
651 | }
652 |
653 | TEST_CASE("Parser Null Reading", "[parser]")
654 | {
655 | {
656 | Parser parser = parser_from_c_str("key = null");
657 | bool value_bool = false;
658 | CHECK_FALSE(parser.try_read("key", value_bool, true));
659 | CHECK(value_bool == true);
660 | double value_dbl = 0.0;
661 | CHECK_FALSE(parser.try_read("key", value_dbl, 1.0));
662 | CHECK(value_dbl == 1.0);
663 | CHECK(parser.eof());
664 | CHECK(parser.is_valid());
665 | }
666 | }
667 |
--------------------------------------------------------------------------------
/tests/sources/test_string_view.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #include "catch2.impl.h"
26 |
27 | #include
28 |
29 | #include
30 |
31 | using namespace sjson;
32 |
33 | TEST_CASE("StringView", "[string]")
34 | {
35 | CHECK(StringView() == StringView(""));
36 | CHECK(StringView() == "");
37 | CHECK(StringView().size() == 0);
38 | CHECK(StringView().c_str() != nullptr);
39 | CHECK(StringView("").size() == 0);
40 | CHECK(StringView("").c_str() != nullptr);
41 |
42 | const char* str0 = "this is a test string";
43 | const char* str1 = "this is not a test string";
44 | const char* str2 = "this is a test asset!";
45 |
46 | CHECK(StringView(str0) == str0);
47 | CHECK(StringView(str0) != str1);
48 | CHECK(StringView(str0) != str2);
49 | CHECK(StringView(str0) == StringView(str0));
50 | CHECK(StringView(str0) != StringView(str1));
51 | CHECK(StringView(str0) != StringView(str2));
52 | CHECK(StringView(str0).c_str() == str0);
53 | CHECK(StringView(str0).size() == std::strlen(str0));
54 | CHECK(StringView(str0, 4) == StringView(str1, 4));
55 | CHECK(StringView(str0, 4) == StringView("this"));
56 |
57 | StringView view0(str0);
58 | CHECK(view0 == str0);
59 | view0 = str1;
60 | CHECK(view0 == str1);
61 |
62 | CHECK(StringView().empty() == true);
63 | CHECK(StringView("").empty() == true);
64 | CHECK(view0.empty() == false);
65 |
66 | CHECK(view0[0] == 't');
67 | CHECK(view0[1] == 'h');
68 | CHECK(view0[2] == 'i');
69 | CHECK(view0[3] == 's');
70 | CHECK(view0[4] == ' ');
71 | CHECK(view0[5] == 'i');
72 | CHECK(view0[view0.size() - 1] == 'g');
73 | CHECK_THROWS(view0[view0.size()]);
74 | }
75 |
--------------------------------------------------------------------------------
/tests/sources/test_writer.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2018 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #include "catch2.impl.h"
26 |
27 | #include
28 | #include
29 |
30 | #include
31 | #include
32 |
33 | using namespace sjson;
34 |
35 | class StringStreamWriter final : public StreamWriter
36 | {
37 | public:
38 | StringStreamWriter() = default;
39 | StringStreamWriter(const StringStreamWriter&) = delete;
40 | StringStreamWriter& operator=(const StringStreamWriter&) = delete;
41 |
42 | virtual void write(const void* buffer, size_t buffer_size) override
43 | {
44 | m_buffer.sputn(sjson_impl::bit_cast(buffer), static_cast(buffer_size));
45 | }
46 |
47 | std::string str() const { return m_buffer.str(); }
48 |
49 | private:
50 | std::stringbuf m_buffer;
51 | };
52 |
53 | TEST_CASE("Writer Object Bool Writing", "[writer]")
54 | {
55 | {
56 | StringStreamWriter str_writer;
57 | Writer writer(str_writer);
58 | writer.insert("key", true);
59 | CHECK(str_writer.str() == "key = true\r\n");
60 | }
61 |
62 | {
63 | StringStreamWriter str_writer;
64 | Writer writer(str_writer);
65 | writer.insert("key", false);
66 | CHECK(str_writer.str() == "key = false\r\n");
67 | }
68 |
69 | {
70 | StringStreamWriter str_writer;
71 | Writer writer(str_writer);
72 | writer["key"] = true;
73 | CHECK(str_writer.str() == "key = true\r\n");
74 | }
75 |
76 | {
77 | StringStreamWriter str_writer;
78 | Writer writer(str_writer);
79 | writer["key"] = false;
80 | CHECK(str_writer.str() == "key = false\r\n");
81 | }
82 | }
83 |
84 | TEST_CASE("Writer Object String Writing", "[writer]")
85 | {
86 | {
87 | StringStreamWriter str_writer;
88 | Writer writer(str_writer);
89 | writer.insert("key", "some string");
90 | CHECK(str_writer.str() == "key = \"some string\"\r\n");
91 | }
92 |
93 | {
94 | StringStreamWriter str_writer;
95 | Writer writer(str_writer);
96 | writer["key"] = "some string";
97 | CHECK(str_writer.str() == "key = \"some string\"\r\n");
98 | }
99 |
100 | {
101 | StringStreamWriter str_writer;
102 | Writer writer(str_writer);
103 | writer.insert("key", "some\tstring");
104 | CHECK(str_writer.str() == "key = \"some\tstring\"\r\n");
105 | }
106 |
107 | {
108 | StringStreamWriter str_writer;
109 | Writer writer(str_writer);
110 | writer["key"] = "some\tstring";
111 | CHECK(str_writer.str() == "key = \"some\tstring\"\r\n");
112 | }
113 |
114 | {
115 | StringStreamWriter str_writer;
116 | Writer writer(str_writer);
117 | writer.insert("key", "some\nstring");
118 | CHECK(str_writer.str() == "key = \"some\nstring\"\r\n");
119 | }
120 |
121 | {
122 | StringStreamWriter str_writer;
123 | Writer writer(str_writer);
124 | writer["key"] = "some\nstring";
125 | CHECK(str_writer.str() == "key = \"some\nstring\"\r\n");
126 | }
127 |
128 | {
129 | StringStreamWriter str_writer;
130 | Writer writer(str_writer);
131 | writer.insert("key", "some\"string");
132 | CHECK(str_writer.str() == "key = \"some\"string\"\r\n");
133 | }
134 |
135 | {
136 | StringStreamWriter str_writer;
137 | Writer writer(str_writer);
138 | writer["key"] = "some\"string";
139 | CHECK(str_writer.str() == "key = \"some\"string\"\r\n");
140 | }
141 | }
142 |
143 | TEST_CASE("Writer Object Number Writing", "[writer]")
144 | {
145 | {
146 | StringStreamWriter str_writer;
147 | Writer writer(str_writer);
148 | writer.insert("key", 123.0);
149 | CHECK(str_writer.str() == "key = 123\r\n");
150 | }
151 |
152 | {
153 | StringStreamWriter str_writer;
154 | Writer writer(str_writer);
155 | writer["key"] = 123.0;
156 | CHECK(str_writer.str() == "key = 123\r\n");
157 | }
158 |
159 | {
160 | StringStreamWriter str_writer;
161 | Writer writer(str_writer);
162 | writer.insert("key", 123.456);
163 | CHECK(str_writer.str() == "key = 123.456\r\n");
164 | }
165 |
166 | {
167 | StringStreamWriter str_writer;
168 | Writer writer(str_writer);
169 | writer["key"] = 123.456;
170 | CHECK(str_writer.str() == "key = 123.456\r\n");
171 | }
172 |
173 | {
174 | StringStreamWriter str_writer;
175 | Writer writer(str_writer);
176 | writer.insert("key", std::nan(""));
177 | CHECK(str_writer.str() == "key = \"nan\"\r\n");
178 | }
179 |
180 | {
181 | StringStreamWriter str_writer;
182 | Writer writer(str_writer);
183 | writer["key"] = std::nan("");
184 | CHECK(str_writer.str() == "key = \"nan\"\r\n");
185 | }
186 |
187 | {
188 | StringStreamWriter str_writer;
189 | Writer writer(str_writer);
190 | writer.insert("key", std::numeric_limits::infinity());
191 | CHECK(str_writer.str() == "key = \"inf\"\r\n");
192 | }
193 |
194 | {
195 | StringStreamWriter str_writer;
196 | Writer writer(str_writer);
197 | writer["key"] = std::numeric_limits::infinity();
198 | CHECK(str_writer.str() == "key = \"inf\"\r\n");
199 | }
200 |
201 | {
202 | StringStreamWriter str_writer;
203 | Writer writer(str_writer);
204 | writer.insert("key", -std::numeric_limits::infinity());
205 | CHECK(str_writer.str() == "key = \"-inf\"\r\n");
206 | }
207 |
208 | {
209 | StringStreamWriter str_writer;
210 | Writer writer(str_writer);
211 | writer["key"] = -std::numeric_limits::infinity();
212 | CHECK(str_writer.str() == "key = \"-inf\"\r\n");
213 | }
214 |
215 | {
216 | StringStreamWriter str_writer;
217 | Writer writer(str_writer);
218 | writer.insert("key", 123.0F);
219 | CHECK(str_writer.str() == "key = 123\r\n");
220 | }
221 |
222 | {
223 | StringStreamWriter str_writer;
224 | Writer writer(str_writer);
225 | writer["key"] = 123.0F;
226 | CHECK(str_writer.str() == "key = 123\r\n");
227 | }
228 |
229 | {
230 | StringStreamWriter str_writer;
231 | Writer writer(str_writer);
232 | writer.insert("key", 123.5F);
233 | CHECK(str_writer.str() == "key = 123.5\r\n");
234 | }
235 |
236 | {
237 | StringStreamWriter str_writer;
238 | Writer writer(str_writer);
239 | writer["key"] = 123.5F;
240 | CHECK(str_writer.str() == "key = 123.5\r\n");
241 | }
242 |
243 | {
244 | StringStreamWriter str_writer;
245 | Writer writer(str_writer);
246 | writer.insert("key", std::nanf(""));
247 | CHECK(str_writer.str() == "key = \"nan\"\r\n");
248 | }
249 |
250 | {
251 | StringStreamWriter str_writer;
252 | Writer writer(str_writer);
253 | writer["key"] = std::nanf("");
254 | CHECK(str_writer.str() == "key = \"nan\"\r\n");
255 | }
256 |
257 | {
258 | StringStreamWriter str_writer;
259 | Writer writer(str_writer);
260 | writer.insert("key", std::numeric_limits::infinity());
261 | CHECK(str_writer.str() == "key = \"inf\"\r\n");
262 | }
263 |
264 | {
265 | StringStreamWriter str_writer;
266 | Writer writer(str_writer);
267 | writer["key"] = std::numeric_limits::infinity();
268 | CHECK(str_writer.str() == "key = \"inf\"\r\n");
269 | }
270 |
271 | {
272 | StringStreamWriter str_writer;
273 | Writer writer(str_writer);
274 | writer.insert("key", -std::numeric_limits::infinity());
275 | CHECK(str_writer.str() == "key = \"-inf\"\r\n");
276 | }
277 |
278 | {
279 | StringStreamWriter str_writer;
280 | Writer writer(str_writer);
281 | writer["key"] = -std::numeric_limits::infinity();
282 | CHECK(str_writer.str() == "key = \"-inf\"\r\n");
283 | }
284 |
285 | {
286 | StringStreamWriter str_writer;
287 | Writer writer(str_writer);
288 | int8_t value = -123;
289 | writer.insert("key", value);
290 | CHECK(str_writer.str() == "key = -123\r\n");
291 | }
292 |
293 | {
294 | StringStreamWriter str_writer;
295 | Writer writer(str_writer);
296 | int8_t value = -123;
297 | writer["key"] = value;
298 | CHECK(str_writer.str() == "key = -123\r\n");
299 | }
300 |
301 | {
302 | StringStreamWriter str_writer;
303 | Writer writer(str_writer);
304 | uint8_t value = 123;
305 | writer.insert("key", value);
306 | CHECK(str_writer.str() == "key = 123\r\n");
307 | }
308 |
309 | {
310 | StringStreamWriter str_writer;
311 | Writer writer(str_writer);
312 | uint8_t value = 123;
313 | writer["key"] = value;
314 | CHECK(str_writer.str() == "key = 123\r\n");
315 | }
316 |
317 | {
318 | StringStreamWriter str_writer;
319 | Writer writer(str_writer);
320 | int16_t value = -1234;
321 | writer.insert("key", value);
322 | CHECK(str_writer.str() == "key = -1234\r\n");
323 | }
324 |
325 | {
326 | StringStreamWriter str_writer;
327 | Writer writer(str_writer);
328 | int16_t value = -1234;
329 | writer["key"] = value;
330 | CHECK(str_writer.str() == "key = -1234\r\n");
331 | }
332 |
333 | {
334 | StringStreamWriter str_writer;
335 | Writer writer(str_writer);
336 | uint16_t value = 1234;
337 | writer.insert("key", value);
338 | CHECK(str_writer.str() == "key = 1234\r\n");
339 | }
340 |
341 | {
342 | StringStreamWriter str_writer;
343 | Writer writer(str_writer);
344 | uint16_t value = 1234;
345 | writer["key"] = value;
346 | CHECK(str_writer.str() == "key = 1234\r\n");
347 | }
348 |
349 | {
350 | StringStreamWriter str_writer;
351 | Writer writer(str_writer);
352 | int32_t value = -123456;
353 | writer.insert("key", value);
354 | CHECK(str_writer.str() == "key = -123456\r\n");
355 | }
356 |
357 | {
358 | StringStreamWriter str_writer;
359 | Writer writer(str_writer);
360 | int32_t value = -123456;
361 | writer["key"] = value;
362 | CHECK(str_writer.str() == "key = -123456\r\n");
363 | }
364 |
365 | {
366 | StringStreamWriter str_writer;
367 | Writer writer(str_writer);
368 | uint32_t value = 123456;
369 | writer.insert("key", value);
370 | CHECK(str_writer.str() == "key = 123456\r\n");
371 | }
372 |
373 | {
374 | StringStreamWriter str_writer;
375 | Writer writer(str_writer);
376 | uint32_t value = 123456;
377 | writer["key"] = value;
378 | CHECK(str_writer.str() == "key = 123456\r\n");
379 | }
380 |
381 | {
382 | StringStreamWriter str_writer;
383 | Writer writer(str_writer);
384 | int64_t value = -1234567890123456LL;
385 | writer.insert("key", value);
386 | CHECK(str_writer.str() == "key = -1234567890123456\r\n");
387 | }
388 |
389 | {
390 | StringStreamWriter str_writer;
391 | Writer writer(str_writer);
392 | int64_t value = -1234567890123456LL;
393 | writer["key"] = value;
394 | CHECK(str_writer.str() == "key = -1234567890123456\r\n");
395 | }
396 |
397 | {
398 | StringStreamWriter str_writer;
399 | Writer writer(str_writer);
400 | uint64_t value = 1234567890123456ULL;
401 | writer.insert("key", value);
402 | CHECK(str_writer.str() == "key = 1234567890123456\r\n");
403 | }
404 |
405 | {
406 | StringStreamWriter str_writer;
407 | Writer writer(str_writer);
408 | uint64_t value = 1234567890123456ULL;
409 | writer["key"] = value;
410 | CHECK(str_writer.str() == "key = 1234567890123456\r\n");
411 | }
412 | }
413 |
414 | TEST_CASE("Writer Object Array Writing", "[writer]")
415 | {
416 | {
417 | StringStreamWriter str_writer;
418 | Writer writer(str_writer);
419 | writer.insert("key", [](ArrayWriter& /*array_writer*/)
420 | {
421 | });
422 | CHECK(str_writer.str() == "key = [ ]\r\n");
423 | }
424 |
425 | {
426 | StringStreamWriter str_writer;
427 | Writer writer(str_writer);
428 | writer.insert("key", [](ArrayWriter& array_writer)
429 | {
430 | array_writer.push(123.5);
431 | array_writer.push(456.5);
432 | });
433 | CHECK(str_writer.str() == "key = [ 123.5, 456.5 ]\r\n");
434 | }
435 |
436 | {
437 | StringStreamWriter str_writer;
438 | Writer writer(str_writer);
439 | writer["key"] = [](ArrayWriter& array_writer)
440 | {
441 | array_writer.push(123.5);
442 | array_writer.push(456.5);
443 | };
444 | CHECK(str_writer.str() == "key = [ 123.5, 456.5 ]\r\n");
445 | }
446 | }
447 |
448 | TEST_CASE("Writer Object Object Writing", "[writer]")
449 | {
450 | {
451 | StringStreamWriter str_writer;
452 | Writer writer(str_writer);
453 | writer.insert("key", [](ObjectWriter& /*object_writer*/)
454 | {
455 | });
456 | CHECK(str_writer.str() == "key = {\r\n}\r\n");
457 | }
458 |
459 | {
460 | StringStreamWriter str_writer;
461 | Writer writer(str_writer);
462 | writer.insert("key", [](ObjectWriter& object_writer)
463 | {
464 | object_writer["key0"] = 123.5;
465 | object_writer["key1"] = 456.5;
466 | });
467 | CHECK(str_writer.str() == "key = {\r\n\tkey0 = 123.5\r\n\tkey1 = 456.5\r\n}\r\n");
468 | }
469 |
470 | {
471 | StringStreamWriter str_writer;
472 | Writer writer(str_writer);
473 | writer["key"] = [](ObjectWriter& object_writer)
474 | {
475 | object_writer["key0"] = 123.5;
476 | object_writer["key1"] = 456.5;
477 | };
478 | CHECK(str_writer.str() == "key = {\r\n\tkey0 = 123.5\r\n\tkey1 = 456.5\r\n}\r\n");
479 | }
480 | }
481 |
482 | TEST_CASE("Writer Array Bool Writing", "[writer]")
483 | {
484 | {
485 | StringStreamWriter str_writer;
486 | Writer writer(str_writer);
487 | writer.insert("key", [](ArrayWriter& array_writer)
488 | {
489 | array_writer.push(true);
490 | });
491 | CHECK(str_writer.str() == "key = [ true ]\r\n");
492 | }
493 |
494 | {
495 | StringStreamWriter str_writer;
496 | Writer writer(str_writer);
497 | writer.insert("key", [](ArrayWriter& array_writer)
498 | {
499 | array_writer.push(false);
500 | });
501 | CHECK(str_writer.str() == "key = [ false ]\r\n");
502 | }
503 | }
504 |
505 | TEST_CASE("Writer Array String Writing", "[writer]")
506 | {
507 | {
508 | StringStreamWriter str_writer;
509 | Writer writer(str_writer);
510 | writer.insert("key", [](ArrayWriter& array_writer)
511 | {
512 | array_writer.push("some string");
513 | });
514 | CHECK(str_writer.str() == "key = [ \"some string\" ]\r\n");
515 | }
516 |
517 | {
518 | StringStreamWriter str_writer;
519 | Writer writer(str_writer);
520 | writer.insert("key", [](ArrayWriter& array_writer)
521 | {
522 | array_writer.push("some\tstring");
523 | });
524 | CHECK(str_writer.str() == "key = [ \"some\tstring\" ]\r\n");
525 | }
526 |
527 | {
528 | StringStreamWriter str_writer;
529 | Writer writer(str_writer);
530 | writer.insert("key", [](ArrayWriter& array_writer)
531 | {
532 | array_writer.push("some\nstring");
533 | });
534 | CHECK(str_writer.str() == "key = [ \"some\nstring\" ]\r\n");
535 | }
536 |
537 | {
538 | StringStreamWriter str_writer;
539 | Writer writer(str_writer);
540 | writer.insert("key", [](ArrayWriter& array_writer)
541 | {
542 | array_writer.push("some\"string");
543 | });
544 | CHECK(str_writer.str() == "key = [ \"some\"string\" ]\r\n");
545 | }
546 | }
547 |
548 | TEST_CASE("Writer Array Number Writing", "[writer]")
549 | {
550 | {
551 | StringStreamWriter str_writer;
552 | Writer writer(str_writer);
553 | writer.insert("key", [](ArrayWriter& array_writer)
554 | {
555 | array_writer.push(123.0);
556 | });
557 | CHECK(str_writer.str() == "key = [ 123 ]\r\n");
558 | }
559 |
560 | {
561 | StringStreamWriter str_writer;
562 | Writer writer(str_writer);
563 | writer.insert("key", [](ArrayWriter& array_writer)
564 | {
565 | array_writer.push(123.456);
566 | });
567 | CHECK(str_writer.str() == "key = [ 123.456 ]\r\n");
568 | }
569 |
570 | {
571 | StringStreamWriter str_writer;
572 | Writer writer(str_writer);
573 | writer.insert("key", [](ArrayWriter& array_writer)
574 | {
575 | array_writer.push(std::nan(""));
576 | array_writer.push(std::numeric_limits::infinity());
577 | array_writer.push(-std::numeric_limits::infinity());
578 | });
579 | CHECK(str_writer.str() == "key = [ \"nan\", \"inf\", \"-inf\" ]\r\n");
580 | }
581 |
582 | {
583 | StringStreamWriter str_writer;
584 | Writer writer(str_writer);
585 | writer.insert("key", [](ArrayWriter& array_writer)
586 | {
587 | array_writer.push(123.0F);
588 | });
589 | CHECK(str_writer.str() == "key = [ 123 ]\r\n");
590 | }
591 |
592 | {
593 | StringStreamWriter str_writer;
594 | Writer writer(str_writer);
595 | writer.insert("key", [](ArrayWriter& array_writer)
596 | {
597 | array_writer.push(123.5F);
598 | });
599 | CHECK(str_writer.str() == "key = [ 123.5 ]\r\n");
600 | }
601 |
602 | {
603 | StringStreamWriter str_writer;
604 | Writer writer(str_writer);
605 | writer.insert("key", [](ArrayWriter& array_writer)
606 | {
607 | array_writer.push(std::nanf(""));
608 | array_writer.push(std::numeric_limits::infinity());
609 | array_writer.push(-std::numeric_limits::infinity());
610 | });
611 | CHECK(str_writer.str() == "key = [ \"nan\", \"inf\", \"-inf\" ]\r\n");
612 | }
613 |
614 | {
615 | StringStreamWriter str_writer;
616 | Writer writer(str_writer);
617 | writer.insert("key", [](ArrayWriter& array_writer)
618 | {
619 | int8_t value = -123;
620 | array_writer.push(value);
621 | });
622 | CHECK(str_writer.str() == "key = [ -123 ]\r\n");
623 | }
624 |
625 | {
626 | StringStreamWriter str_writer;
627 | Writer writer(str_writer);
628 | writer.insert("key", [](ArrayWriter& array_writer)
629 | {
630 | uint8_t value = 123;
631 | array_writer.push(value);
632 | });
633 | CHECK(str_writer.str() == "key = [ 123 ]\r\n");
634 | }
635 |
636 | {
637 | StringStreamWriter str_writer;
638 | Writer writer(str_writer);
639 | writer.insert("key", [](ArrayWriter& array_writer)
640 | {
641 | int16_t value = -1234;
642 | array_writer.push(value);
643 | });
644 | CHECK(str_writer.str() == "key = [ -1234 ]\r\n");
645 | }
646 |
647 | {
648 | StringStreamWriter str_writer;
649 | Writer writer(str_writer);
650 | writer.insert("key", [](ArrayWriter& array_writer)
651 | {
652 | uint16_t value = 1234;
653 | array_writer.push(value);
654 | });
655 | CHECK(str_writer.str() == "key = [ 1234 ]\r\n");
656 | }
657 |
658 | {
659 | StringStreamWriter str_writer;
660 | Writer writer(str_writer);
661 | writer.insert("key", [](ArrayWriter& array_writer)
662 | {
663 | int32_t value = -123456;
664 | array_writer.push(value);
665 | });
666 | CHECK(str_writer.str() == "key = [ -123456 ]\r\n");
667 | }
668 |
669 | {
670 | StringStreamWriter str_writer;
671 | Writer writer(str_writer);
672 | writer.insert("key", [](ArrayWriter& array_writer)
673 | {
674 | uint32_t value = 123456;
675 | array_writer.push(value);
676 | });
677 | CHECK(str_writer.str() == "key = [ 123456 ]\r\n");
678 | }
679 |
680 | {
681 | StringStreamWriter str_writer;
682 | Writer writer(str_writer);
683 | writer.insert("key", [](ArrayWriter& array_writer)
684 | {
685 | int64_t value = -1234567890123456LL;
686 | array_writer.push(value);
687 | });
688 | CHECK(str_writer.str() == "key = [ -1234567890123456 ]\r\n");
689 | }
690 |
691 | {
692 | StringStreamWriter str_writer;
693 | Writer writer(str_writer);
694 | writer.insert("key", [](ArrayWriter& array_writer)
695 | {
696 | uint64_t value = 1234567890123456ULL;
697 | array_writer.push(value);
698 | });
699 | CHECK(str_writer.str() == "key = [ 1234567890123456 ]\r\n");
700 | }
701 | }
702 |
703 | TEST_CASE("Writer Array Array Writing", "[writer]")
704 | {
705 | {
706 | StringStreamWriter str_writer;
707 | Writer writer(str_writer);
708 | writer.insert("key", [](ArrayWriter& array_writer)
709 | {
710 | array_writer.push([](ArrayWriter& /*array_writer*/)
711 | {
712 | });
713 | });
714 | CHECK(str_writer.str() == "key = [ [ ] ]\r\n");
715 | }
716 |
717 | {
718 | StringStreamWriter str_writer;
719 | Writer writer(str_writer);
720 | writer.insert("key", [](ArrayWriter& array_writer)
721 | {
722 | array_writer.push([](ArrayWriter& array_writer1)
723 | {
724 | array_writer1.push(123.5);
725 | array_writer1.push(456.5);
726 | });
727 | });
728 | CHECK(str_writer.str() == "key = [ [ 123.5, 456.5 ] ]\r\n");
729 | }
730 | }
731 |
732 | TEST_CASE("Writer Array Object Writing", "[writer]")
733 | {
734 | {
735 | StringStreamWriter str_writer;
736 | Writer writer(str_writer);
737 | writer.insert("key", [](ArrayWriter& array_writer)
738 | {
739 | array_writer.push([](ObjectWriter& /*object_writer*/)
740 | {
741 | });
742 | });
743 | CHECK(str_writer.str() == "key = [ \r\n\t{\r\n\t}\r\n]\r\n");
744 | }
745 |
746 | {
747 | StringStreamWriter str_writer;
748 | Writer writer(str_writer);
749 | writer.insert("key", [](ArrayWriter& array_writer)
750 | {
751 | array_writer.push([](ObjectWriter& object_writer1)
752 | {
753 | object_writer1["key0"] = 123.5;
754 | object_writer1["key1"] = 456.5;
755 | });
756 | });
757 | CHECK(str_writer.str() == "key = [ \r\n\t{\r\n\t\tkey0 = 123.5\r\n\t\tkey1 = 456.5\r\n\t}\r\n]\r\n");
758 | }
759 | }
760 |
--------------------------------------------------------------------------------
/tests/validate_includes/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required (VERSION 3.2)
2 | project(sjson-cpp_validate_includes CXX)
3 |
4 | # The goal of this project is to generate a single cpp file for every public header
5 | # This will allow us to detect if we are missing an include file during development
6 |
7 | include_directories("${PROJECT_SOURCE_DIR}/../../includes")
8 |
9 | # Grab all of our public header files
10 | file(GLOB ALL_PUBLIC_HEADER_FILES LIST_DIRECTORIES false
11 | ${PROJECT_SOURCE_DIR}/../../includes/sjson/*.h)
12 |
13 | # Generate the single include cpp files
14 | foreach(HEADER_FILE ${ALL_PUBLIC_HEADER_FILES})
15 | # Find the root include directory position
16 | string(FIND ${HEADER_FILE} "sjson" HEADER_FILE_SJSON_CPP_POS REVERSE)
17 |
18 | # Strip the root of the include path
19 | string(SUBSTRING ${HEADER_FILE} ${HEADER_FILE_SJSON_CPP_POS} -1 HEADER_INCLUDE_PATH)
20 |
21 | # Configure our cpp file content
22 | set(SJSON_CPP_SINGLE_INCLUDE_NAME ${HEADER_INCLUDE_PATH})
23 |
24 | # Sanitize our filename so we can generate a unique cpp file for it
25 | string(REPLACE "/" "_" HEADER_SANITIZED_FILENAME ${HEADER_INCLUDE_PATH})
26 | string(REPLACE "\\" "_" HEADER_SANITIZED_FILENAME ${HEADER_SANITIZED_FILENAME})
27 |
28 | # Generate our single include cpp file
29 | configure_file(${PROJECT_SOURCE_DIR}/single_include.cpp.in single_include_${HEADER_SANITIZED_FILENAME}.cpp @ONLY)
30 | endforeach(HEADER_FILE)
31 |
32 | # Grab all of our main source files
33 | file(GLOB_RECURSE ALL_MAIN_SOURCE_FILES LIST_DIRECTORIES false
34 | ${PROJECT_SOURCE_DIR}/*.cpp
35 | ${PROJECT_BINARY_DIR}/*.cpp)
36 |
37 | create_source_groups("${ALL_MAIN_SOURCE_FILES}" ${PROJECT_SOURCE_DIR})
38 |
39 | add_library(${PROJECT_NAME} STATIC ${ALL_MAIN_SOURCE_FILES})
40 |
41 | setup_default_compiler_flags(${PROJECT_NAME})
42 |
--------------------------------------------------------------------------------
/tests/validate_includes/dummy.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2024 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | // We define a single symbol here to avoid a warning when we build our static library
26 | // to validate includes
27 | void some_function() {}
28 |
--------------------------------------------------------------------------------
/tests/validate_includes/single_include.cpp.in:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | // The MIT License (MIT)
3 | //
4 | // Copyright (c) 2024 Nicholas Frechette, Cody Jones, and sjson-cpp contributors
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 | ////////////////////////////////////////////////////////////////////////////////
24 |
25 | #include <@SJSON_CPP_SINGLE_INCLUDE_NAME@>
26 |
--------------------------------------------------------------------------------
/tools/appveyor_ci.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | REM Unpack arguments
4 | SET WORKER_IMAGE=%1
5 | SET PLATFORM=%2
6 | SET CONFIG=%3
7 | SET TOOLCHAIN=%4
8 | SET PYTHON_PATH=%5
9 |
10 | echo Worker image: %WORKER_IMAGE%
11 | echo Platform: %PLATFORM%
12 | echo Config: %CONFIG%
13 | echo Toolchain: %TOOLCHAIN%
14 | echo Python path: %PYTHON_PATH%
15 |
16 | REM Convert the build image and toolchain into our compiler string
17 | IF /i %TOOLCHAIN%==msvc GOTO :msvc
18 | IF /i %TOOLCHAIN%==clang GOTO :clang
19 |
20 | echo Unknown toolchain: %TOOLCHAIN%
21 | exit /B 1
22 |
23 | :msvc
24 | IF /i %WORKER_IMAGE%=="Visual Studio 2015" SET COMPILER=vs2015
25 | IF /i %WORKER_IMAGE%=="Visual Studio 2017" SET COMPILER=vs2017
26 | IF /i %WORKER_IMAGE%=="Visual Studio 2019" SET COMPILER=vs2019
27 | IF /i %WORKER_IMAGE%=="Previous Visual Studio 2019" SET COMPILER=vs2019
28 | GOTO :next
29 |
30 | :clang
31 | IF /i %WORKER_IMAGE%=="Visual Studio 2019" SET COMPILER=vs2019-clang
32 | IF /i %WORKER_IMAGE%=="Previous Visual Studio 2019" SET COMPILER=vs2019-clang
33 |
34 | REM HACK!!! Disable clang build for now with appveyor since vcpkg breaks the compiler detection of cmake
35 | REM Fake build success
36 | exit /B 0
37 |
38 | GOTO :next
39 |
40 | :next
41 | REM Set our switch if we need to run unit tests
42 | SET UNIT_TEST_FLAG=-unit_test
43 | IF /i %PLATFORM%==arm64 SET UNIT_TEST_FLAG=
44 |
45 | REM If PYTHON_PATH isn't set, assume it is in PATH
46 | IF NOT DEFINED PYTHON_PATH SET PYTHON_PATH=python.exe
47 |
48 | REM Build and run unit tests
49 | %PYTHON_PATH% make.py -build %UNIT_TEST_FLAG% -compiler %COMPILER% -config %CONFIG% -cpu %PLATFORM% -clean
50 | IF NOT %ERRORLEVEL% EQU 0 GOTO :build_failure
51 |
52 | REM Done!
53 | exit /B 0
54 |
55 | :build_failure
56 | echo Build failed!
57 | exit /B 1
58 |
--------------------------------------------------------------------------------
/tools/release_scripts/test_everything.py:
--------------------------------------------------------------------------------
1 | import os
2 | import platform
3 | import shutil
4 | import subprocess
5 | import sys
6 |
7 | def get_platform_compilers():
8 | if platform.system() == 'Windows':
9 | return [ 'vs2015', 'vs2017', 'vs2019', 'vs2019-clang' ]
10 | elif platform.system() == 'Linux':
11 | compilers = []
12 | if shutil.which('g++-5'):
13 | compilers.append('gcc5')
14 | if shutil.which('g++-6'):
15 | compilers.append('gcc6')
16 | if shutil.which('g++-7'):
17 | compilers.append('gcc7')
18 | if shutil.which('g++-8'):
19 | compilers.append('gcc8')
20 | if shutil.which('g++-9'):
21 | compilers.append('gcc9')
22 | if shutil.which('g++-10'):
23 | compilers.append('gcc10')
24 |
25 | if shutil.which('clang++-4.0'):
26 | compilers.append('clang4')
27 | if shutil.which('clang++-5.0'):
28 | compilers.append('clang5')
29 | if shutil.which('clang++-6.0'):
30 | compilers.append('clang6')
31 | if shutil.which('clang++-7'):
32 | compilers.append('clang7')
33 | if shutil.which('clang++-8'):
34 | compilers.append('clang8')
35 | if shutil.which('clang++-9'):
36 | compilers.append('clang9')
37 | if shutil.which('clang++-10'):
38 | compilers.append('clang10')
39 | if shutil.which('clang++-11'):
40 | compilers.append('clang11')
41 |
42 | return compilers
43 | elif platform.system() == 'Darwin':
44 | return [ 'osx' ]
45 | else:
46 | print('Unknown platform!')
47 | sys.exit(1)
48 |
49 | def get_python_exe_name():
50 | if platform.system() == 'Windows':
51 | return 'python'
52 | else:
53 | return 'python3'
54 |
55 | if __name__ == "__main__":
56 | os.environ['PYTHONIOENCODING'] = 'utf_8'
57 |
58 | configs = [ 'debug', 'release' ]
59 | archs = [ 'x86', 'x64' ]
60 | compilers = get_platform_compilers()
61 | python_exe = get_python_exe_name()
62 |
63 | if platform.system() == 'Darwin':
64 | result = subprocess.check_output(['xcodebuild', '-version']).decode("utf-8")
65 | if 'Xcode 11' in result:
66 | archs.remove('x86')
67 |
68 | cmd_args = []
69 | for config in configs:
70 | for arch in archs:
71 | for compiler in compilers:
72 | args = [python_exe, 'make.py', '-compiler', compiler, '-cpu', arch, '-config', config, '-build', '-unit_test', '-clean']
73 | cmd_args.append([x for x in args if x])
74 |
75 | if platform.system() == 'Windows':
76 | for config in configs:
77 | # Windows ARM
78 | args = [python_exe, 'make.py', '-compiler', 'vs2017', '-cpu', 'arm64', '-config', config, '-build', '-clean']
79 | cmd_args.append([x for x in args if x])
80 |
81 | # Android
82 | args = [python_exe, 'make.py', '-compiler', 'android', '-cpu', 'armv7', '-config', config, '-build', '-clean']
83 | cmd_args.append([x for x in args if x])
84 | args = [python_exe, 'make.py', '-compiler', 'android', '-cpu', 'arm64', '-config', config, '-build', '-clean']
85 | cmd_args.append([x for x in args if x])
86 | elif platform.system() == 'Darwin':
87 | for config in configs:
88 | # iOS
89 | args = [python_exe, 'make.py', '-compiler', 'ios', '-config', config, '-build', '-clean']
90 | cmd_args.append([x for x in args if x])
91 |
92 | if platform.system() == 'Darwin' or platform.system() == 'Linux':
93 | for config in configs:
94 | # Emscripten
95 | args = [python_exe, 'make.py', '-compiler', 'emscripten', '-config', config, '-build', '-unit_test', '-clean']
96 | cmd_args.append([x for x in args if x])
97 |
98 | root_dir = os.path.join(os.getcwd(), '../..')
99 | os.chdir(root_dir)
100 |
101 | for args in cmd_args:
102 | print('Running command: "{}" ...'.format(" ".join(args)))
103 | try:
104 | if 'android' in args:
105 | subprocess.check_call(args)
106 | else:
107 | subprocess.check_output(args)
108 | except subprocess.CalledProcessError as e:
109 | print('Failed command: {}'.format(" ".join(args)))
110 | print(e.output.decode(sys.stdout.encoding))
111 | sys.exit(1)
112 |
113 | print('Done!')
114 | sys.exit(0)
115 |
--------------------------------------------------------------------------------
/tools/setup_linux_compiler.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Extract our command line arguments
4 | COMPILER=$1
5 |
6 | # Convert our GCC compiler into a list of packages it needs
7 | if [[ $COMPILER == gcc5 ]]; then
8 | PACKAGES="g++-5 g++-5-multilib g++-multilib"
9 | elif [[ $COMPILER == gcc6 ]]; then
10 | PACKAGES="g++-6 g++-6-multilib g++-multilib"
11 | elif [[ $COMPILER == gcc7 ]]; then
12 | PACKAGES="g++-7 g++-7-multilib g++-multilib"
13 | elif [[ $COMPILER == gcc8 ]]; then
14 | PACKAGES="g++-8 g++-8-multilib g++-multilib"
15 | elif [[ $COMPILER == gcc9 ]]; then
16 | PACKAGES="g++-9 g++-9-multilib g++-multilib"
17 | elif [[ $COMPILER == gcc10 ]]; then
18 | PACKAGES="g++-10 g++-10-multilib g++-multilib"
19 | fi
20 |
21 | # If using clang, add our apt source key
22 | if [[ $COMPILER == clang* ]]; then
23 | curl -sSL "http://apt.llvm.org/llvm-snapshot.gpg.key" | sudo -E apt-key add - ;
24 | fi
25 |
26 | # Convert our clang compiler into a list of packages it needs and its source
27 | if [[ $COMPILER == clang4 ]]; then
28 | # clang4 isn't available after xenial
29 | PACKAGES="clang-4.0 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
30 | echo "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
31 | elif [[ $COMPILER == clang5 ]]; then
32 | PACKAGES="clang-5.0 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
33 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-5.0 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
34 | elif [[ $COMPILER == clang6 ]]; then
35 | PACKAGES="clang-6.0 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
36 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-6.0 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
37 | elif [[ $COMPILER == clang7 ]]; then
38 | PACKAGES="clang-7 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
39 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
40 | elif [[ $COMPILER == clang8 ]]; then
41 | PACKAGES="clang-8 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
42 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
43 | elif [[ $COMPILER == clang9 ]]; then
44 | PACKAGES="clang-9 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
45 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
46 | elif [[ $COMPILER == clang10 ]]; then
47 | PACKAGES="clang-10 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
48 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
49 | elif [[ $COMPILER == clang11 ]]; then
50 | PACKAGES="clang-11 libstdc++-5-dev libc6-dev-i386 g++-5-multilib g++-multilib"
51 | echo "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-11 main" | sudo tee -a /etc/apt/sources.list > /dev/null ;
52 | fi
53 |
54 | # Install the packages we need
55 | sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test";
56 | sudo -E apt-get -yq update;
57 | sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install $PACKAGES;
58 |
--------------------------------------------------------------------------------
/tools/setup_osx_compiler.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Extract our command line arguments
4 | COMPILER=$1
5 |
6 | # See Github hosted runners:
7 | # macos-14: https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md
8 | # xcode 14.3.1, 15.0.1, 15.1, 15.2, 15.3, 15.4, 16.0
9 | # macos-13: https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md
10 | # xcode 14.1, 14.2, 14.3.1, 15.0.1, 15.1, 15.2
11 | # macos-12: https://github.com/actions/runner-images/blob/main/images/macos/macos-12-Readme.md
12 | # xcode 13.1, 12.2.1, 13.3.1, 13.4.1, 14.1, 14.2
13 | # maxos-11: https://github.com/actions/runner-images/blob/main/images/macos/macos-11-Readme.md
14 | # xcode 11.7, 12.4, 12.5.1, 13.0, 13.1, 13.2.1
15 | # maxos-10.15: https://github.com/actions/runner-images/blob/main/images/macos/macos-10.15-Readme.md
16 | # xcode 10.3, 11.2.1, 11.3.1, 11.4.1, 11.5, 11.6, 11.7, 12, 12.1, 12.1.1, 12.2, 12.3, 12.4
17 |
18 | # Convert our compiler string into our XCode path
19 | # Paths must match Github Action virtual images
20 | if [[ $COMPILER == xcode10 ]]; then
21 | XCODE_PATH="/Applications/Xcode_10.3.app"
22 | elif [[ $COMPILER == xcode11 ]]; then
23 | XCODE_PATH="/Applications/Xcode_11.7.app"
24 | elif [[ $COMPILER == xcode12 ]]; then
25 | XCODE_PATH="/Applications/Xcode_12.5.1.app"
26 | elif [[ $COMPILER == xcode13 ]]; then
27 | XCODE_PATH="/Applications/Xcode_13.2.1.app"
28 | elif [[ $COMPILER == xcode14 ]]; then
29 | XCODE_PATH="/Applications/Xcode_14.3.1.app"
30 | elif [[ $COMPILER == xcode15 ]]; then
31 | XCODE_PATH="/Applications/Xcode_15.2.app"
32 | elif [[ $COMPILER == xcode16 ]]; then
33 | XCODE_PATH="/Applications/Xcode_16.0.app"
34 | fi
35 |
36 | # Select our XCode version
37 | sudo xcode-select -s $XCODE_PATH/Contents/Developer;
38 |
--------------------------------------------------------------------------------
/tools/vs_visualizers/sjson-cpp.natvis:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {m_c_str,[m_length]s8}
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------