OpenShot Audio Library | OpenShotAudio 0.4.0
juce_JSONSerialisation_test.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26struct TypeWithExternalUnifiedSerialisation
27{
28 int a;
29 std::string b;
30 std::vector<int> c;
31 std::map<std::string, int> d;
32
33 auto operator== (const TypeWithExternalUnifiedSerialisation& other) const
34 {
35 const auto tie = [] (const auto& x) { return std::tie (x.a, x.b, x.c, x.d); };
36 return tie (*this) == tie (other);
37 }
38
39 auto operator!= (const TypeWithExternalUnifiedSerialisation& other) const { return ! operator== (other); }
40};
41
42template <>
43struct SerialisationTraits<TypeWithExternalUnifiedSerialisation>
44{
45 static constexpr auto marshallingVersion = 2;
46
47 template <typename Archive, typename T>
48 static void serialise (Archive& archive, T& t)
49 {
50 archive (named ("a", t.a),
51 named ("b", t.b),
52 named ("c", t.c),
53 named ("d", t.d));
54 }
55};
56
57// Now that the serialiser trait is visible, it should be detected
58static_assert (detail::serialisationKind<TypeWithExternalUnifiedSerialisation> == detail::SerialisationKind::external);
59
60struct TypeWithInternalUnifiedSerialisation
61{
62 double a;
63 float b;
64 String c;
65 StringArray d;
66
67 auto operator== (const TypeWithInternalUnifiedSerialisation& other) const
68 {
69 const auto tie = [] (const auto& x) { return std::tie (x.a, x.b, x.c, x.d); };
70 return tie (*this) == tie (other);
71 }
72
73 auto operator!= (const TypeWithInternalUnifiedSerialisation& other) const { return ! operator== (other); }
74
75 static constexpr auto marshallingVersion = 5;
76
77 template <typename Archive, typename T>
78 static void serialise (Archive& archive, T& t)
79 {
80 archive (named ("a", t.a),
81 named ("b", t.b),
82 named ("c", t.c),
83 named ("d", t.d));
84 }
85};
86
87static_assert (detail::serialisationKind<TypeWithInternalUnifiedSerialisation> == detail::SerialisationKind::internal);
88
89struct TypeWithExternalSplitSerialisation
90{
91 std::optional<String> a;
92 Array<int> b;
93
94 auto operator== (const TypeWithExternalSplitSerialisation& other) const
95 {
96 const auto tie = [] (const auto& x) { return std::tie (x.a, x.b); };
97 return tie (*this) == tie (other);
98 }
99
100 auto operator!= (const TypeWithExternalSplitSerialisation& other) const { return ! operator== (other); }
101};
102
103template <>
104struct SerialisationTraits<TypeWithExternalSplitSerialisation>
105{
106 static constexpr auto marshallingVersion = 10;
107
108 template <typename Archive>
109 static void load (Archive& archive, TypeWithExternalSplitSerialisation& t)
110 {
111 std::optional<String> a;
112 Array<String> hexStrings;
113 archive (named ("a", a), named ("b", hexStrings));
114
115 Array<int> b;
116
117 for (auto& i : hexStrings)
118 b.add (i.getHexValue32());
119
120 t = { a, b };
121 }
122
123 template <typename Archive>
124 static void save (Archive& archive, const TypeWithExternalSplitSerialisation& t)
125 {
126 Array<String> hexStrings;
127
128 for (auto& i : t.b)
129 hexStrings.add ("0x" + String::toHexString (i));
130
131 archive (named ("a", t.a), named ("b", hexStrings));
132 }
133};
134
135// Now that the serialiser trait is visible, it should be detected
136static_assert (detail::serialisationKind<TypeWithExternalSplitSerialisation> == detail::SerialisationKind::external);
137
138// Check that serialisation kinds are correctly detected for primitives
139static_assert (detail::serialisationKind<bool> == detail::SerialisationKind::primitive);
140static_assert (detail::serialisationKind< int8_t> == detail::SerialisationKind::primitive);
141static_assert (detail::serialisationKind< uint8_t> == detail::SerialisationKind::primitive);
142static_assert (detail::serialisationKind< int16_t> == detail::SerialisationKind::primitive);
143static_assert (detail::serialisationKind<uint16_t> == detail::SerialisationKind::primitive);
144static_assert (detail::serialisationKind< int32_t> == detail::SerialisationKind::primitive);
145static_assert (detail::serialisationKind<uint32_t> == detail::SerialisationKind::primitive);
146static_assert (detail::serialisationKind< int64_t> == detail::SerialisationKind::primitive);
147static_assert (detail::serialisationKind<uint64_t> == detail::SerialisationKind::primitive);
148static_assert (detail::serialisationKind<float> == detail::SerialisationKind::primitive);
149static_assert (detail::serialisationKind<double> == detail::SerialisationKind::primitive);
150static_assert (detail::serialisationKind<std::byte> == detail::SerialisationKind::primitive);
151static_assert (detail::serialisationKind<String> == detail::SerialisationKind::primitive);
152
153// Check that serialisation is disabled for types with no serialsation defined
154static_assert (detail::serialisationKind<Logger> == detail::SerialisationKind::none);
155static_assert (detail::serialisationKind<CriticalSection> == detail::SerialisationKind::none);
156
157struct TypeWithInternalSplitSerialisation
158{
159 std::string a;
160 Array<int> b;
161
162 auto operator== (const TypeWithInternalSplitSerialisation& other) const
163 {
164 const auto tie = [] (const auto& x) { return std::tie (x.a, x.b); };
165 return tie (*this) == tie (other);
166 }
167
168 auto operator!= (const TypeWithInternalSplitSerialisation& other) const { return ! operator== (other); }
169
170 static constexpr auto marshallingVersion = 1;
171
172 template <typename Archive>
173 static void load (Archive& archive, TypeWithInternalSplitSerialisation& t)
174 {
175 std::string a;
176 Array<String> hexStrings;
177 archive (named ("a", a), named ("b", hexStrings));
178
179 Array<int> b;
180
181 for (auto& i : hexStrings)
182 b.add (i.getHexValue32());
183
184 t = { a, b };
185 }
186
187 template <typename Archive>
188 static void save (Archive& archive, const TypeWithInternalSplitSerialisation& t)
189 {
190 Array<String> hexStrings;
191
192 for (auto& i : t.b)
193 hexStrings.add ("0x" + String::toHexString (i));
194
195 archive (named ("a", t.a), named ("b", hexStrings));
196 }
197};
198
199static_assert (detail::serialisationKind<TypeWithInternalSplitSerialisation> == detail::SerialisationKind::internal);
200
201struct TypeWithBrokenObjectSerialisation
202{
203 int a;
204 int b;
205
206 static constexpr auto marshallingVersion = std::nullopt;
207
208 template <typename Archive, typename T>
209 static void serialise (Archive& archive, T& t)
210 {
211 // Archiving a named value will start reading/writing an object
212 archive (named ("a", t.a));
213 // Archiving a non-named value will assume that the current node is convertible
214 archive (t.b);
215 }
216};
217
218struct TypeWithBrokenPrimitiveSerialisation
219{
220 int a;
221 int b;
222
223 static constexpr auto marshallingVersion = std::nullopt;
224
225 template <typename Archive, typename T>
226 static void serialise (Archive& archive, T& t)
227 {
228 // Archiving a non-named value will assume that the current node is convertible
229 archive (t.a);
230 // Archiving a named value will fail if the current node holds a non-object type
231 archive (named ("b", t.b));
232 }
233};
234
235struct TypeWithBrokenArraySerialisation
236{
237 static constexpr auto marshallingVersion = std::nullopt;
238
239 template <typename Archive, typename T>
240 static void serialise (Archive& archive, T&)
241 {
242 size_t size = 5;
243 archive (size);
244
245 // serialisationSize should always be serialised first!
246 archive (serialisationSize (size));
247 }
248};
249
250struct TypeWithBrokenNestedSerialisation
251{
252 int a;
253 TypeWithBrokenObjectSerialisation b;
254
255 static constexpr auto marshallingVersion = std::nullopt;
256
257 template <typename Archive, typename T>
258 static void serialise (Archive& archive, T& t)
259 {
260 archive (named ("a", t.a), named ("b", t.b));
261 }
262};
263
264struct TypeWithBrokenDynamicSerialisation
265{
266 std::vector<TypeWithBrokenObjectSerialisation> a;
267
268 static constexpr auto marshallingVersion = std::nullopt;
269
270 template <typename Archive, typename T>
271 static void serialise (Archive& archive, T& t)
272 {
273 archive (t.a);
274 }
275};
276
277struct TypeWithVersionedSerialisation
278{
279 int a{}, b{}, c{}, d{};
280
281 bool operator== (const TypeWithVersionedSerialisation& other) const
282 {
283 const auto tie = [] (const auto& x) { return std::tie (x.a, x.b, x.c, x.d); };
284 return tie (*this) == tie (other);
285 }
286
287 bool operator!= (const TypeWithVersionedSerialisation& other) const { return ! operator== (other); }
288
289 static constexpr auto marshallingVersion = 3;
290
291 template <typename Archive, typename T>
292 static void serialise (Archive& archive, T& t)
293 {
294 archive (named ("a", t.a));
295
296 if (archive.getVersion() >= 1)
297 archive (named ("b", t.b));
298
299 if (archive.getVersion() >= 2)
300 archive (named ("c", t.c));
301
302 if (archive.getVersion() >= 3)
303 archive (named ("d", t.d));
304 }
305};
306
307struct TypeWithRawVarLast
308{
309 int status = 0;
310 String message;
311 var extended;
312
313 bool operator== (const TypeWithRawVarLast& other) const
314 {
315 const auto tie = [] (const auto& x) { return std::tie (x.status, x.message, x.extended); };
316 return tie (*this) == tie (other);
317 }
318
319 bool operator!= (const TypeWithRawVarLast& other) const { return ! operator== (other); }
320
321 static constexpr auto marshallingVersion = std::nullopt;
322
323 template <typename Archive, typename T>
324 static void serialise (Archive& archive, T& t)
325 {
326 archive (named ("status", t.status),
327 named ("message", t.message),
328 named ("extended", t.extended));
329 }
330};
331
332struct TypeWithRawVarFirst
333{
334 int status = 0;
335 String message;
336 var extended;
337
338 bool operator== (const TypeWithRawVarFirst& other) const
339 {
340 const auto tie = [] (const auto& x) { return std::tie (x.status, x.message, x.extended); };
341 return tie (*this) == tie (other);
342 }
343
344 bool operator!= (const TypeWithRawVarFirst& other) const { return ! operator== (other); }
345
346 static constexpr auto marshallingVersion = std::nullopt;
347
348 template <typename Archive, typename T>
349 static void serialise (Archive& archive, T& t)
350 {
351 archive (named ("extended", t.extended),
352 named ("status", t.status),
353 named ("message", t.message));
354 }
355};
356
357struct TypeWithInnerVar
358{
359 int eventId = 0;
360 var payload;
361
362 bool operator== (const TypeWithInnerVar& other) const
363 {
364 const auto tie = [] (const auto& x) { return std::tie (x.eventId, x.payload); };
365 return tie (*this) == tie (other);
366 }
367
368 bool operator!= (const TypeWithInnerVar& other) const { return ! operator== (other); }
369
370 static constexpr auto marshallingVersion = std::nullopt;
371
372 template <typename Archive, typename T>
373 static void serialise (Archive& archive, T& t)
374 {
375 archive (named ("eventId", t.eventId),
376 named ("payload", t.payload));
377 }
378};
379
380class JSONSerialisationTest final : public UnitTest
381{
382public:
383 JSONSerialisationTest() : UnitTest ("JSONSerialisation", UnitTestCategories::json) {}
384
385 void runTest() override
386 {
387 beginTest ("ToVar");
388 {
389 expectDeepEqual (ToVar::convert (false), false);
390 expectDeepEqual (ToVar::convert (true), true);
391 expectDeepEqual (ToVar::convert (1), 1);
392 expectDeepEqual (ToVar::convert (5.0f), 5.0);
393 expectDeepEqual (ToVar::convert (6LL), 6);
394 expectDeepEqual (ToVar::convert ("hello world"), "hello world");
395 expectDeepEqual (ToVar::convert (String ("hello world")), "hello world");
396 expectDeepEqual (ToVar::convert (std::vector<int> { 1, 2, 3 }), Array<var> { 1, 2, 3 });
397 expectDeepEqual (ToVar::convert (TypeWithExternalUnifiedSerialisation { 7,
398 "hello world",
399 { 5, 6, 7 },
400 { { "foo", 4 }, { "bar", 5 } } }),
401 JSONUtils::makeObject ({ { "__version__", 2 },
402 { "a", 7 },
403 { "b", "hello world" },
404 { "c", Array<var> { 5, 6, 7 } },
405 { "d",
406 Array<var> { JSONUtils::makeObject ({ { "first", "bar" },
407 { "second", 5 } }),
408 JSONUtils::makeObject ({ { "first", "foo" },
409 { "second", 4 } }) } } }));
410 expectDeepEqual (ToVar::convert (TypeWithInternalUnifiedSerialisation { 7.89,
411 4.321f,
412 "custom string",
413 { "foo", "bar", "baz" } }),
414 JSONUtils::makeObject ({ { "__version__", 5 },
415 { "a", 7.89 },
416 { "b", 4.321f },
417 { "c", "custom string" },
418 { "d", Array<var> { "foo", "bar", "baz" } } }));
419 expectDeepEqual (ToVar::convert (TypeWithExternalSplitSerialisation { "string", { 1, 2, 3 } }),
420 JSONUtils::makeObject ({ { "__version__", 10 },
421 { "a", JSONUtils::makeObject ({ { "engaged", true }, { "value", "string" } }) },
422 { "b", Array<var> { "0x1", "0x2", "0x3" } } }));
423 expectDeepEqual (ToVar::convert (TypeWithInternalSplitSerialisation { "string", { 16, 32, 48 } }),
424 JSONUtils::makeObject ({ { "__version__", 1 },
425 { "a", "string" },
426 { "b", Array<var> { "0x10", "0x20", "0x30" } } }));
427
428 expect (ToVar::convert (TypeWithBrokenObjectSerialisation { 1, 2 }) == std::nullopt);
429 expect (ToVar::convert (TypeWithBrokenPrimitiveSerialisation { 1, 2 }) == std::nullopt);
430 expect (ToVar::convert (TypeWithBrokenArraySerialisation {}) == std::nullopt);
431 expect (ToVar::convert (TypeWithBrokenNestedSerialisation {}) == std::nullopt);
432 expect (ToVar::convert (TypeWithBrokenDynamicSerialisation { std::vector<TypeWithBrokenObjectSerialisation> (10) }) == std::nullopt);
433
434 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }),
435 JSONUtils::makeObject ({ { "__version__", 3 },
436 { "a", 1 },
437 { "b", 2 },
438 { "c", 3 },
439 { "d", 4 } }));
440 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withVersionIncluded (false)),
441 JSONUtils::makeObject ({ { "a", 1 },
442 { "b", 2 },
443 { "c", 3 },
444 { "d", 4 } }));
445 // Requested explicit version is higher than the type's declared version
446 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (4)),
447 std::nullopt);
448 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (3)),
449 JSONUtils::makeObject ({ { "__version__", 3 },
450 { "a", 1 },
451 { "b", 2 },
452 { "c", 3 },
453 { "d", 4 } }));
454 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (2)),
455 JSONUtils::makeObject ({ { "__version__", 2 },
456 { "a", 1 },
457 { "b", 2 },
458 { "c", 3 } }));
459 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (1)),
460 JSONUtils::makeObject ({ { "__version__", 1 },
461 { "a", 1 },
462 { "b", 2 } }));
463 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (0)),
464 JSONUtils::makeObject ({ { "__version__", 0 },
465 { "a", 1 } }));
466 expectDeepEqual (ToVar::convert (TypeWithVersionedSerialisation { 1, 2, 3, 4 }, ToVar::Options {}.withExplicitVersion (std::nullopt)),
467 JSONUtils::makeObject ({ { "a", 1 } }));
468
469 expectDeepEqual (ToVar::convert (TypeWithRawVarLast { 200, "success", true }),
470 JSONUtils::makeObject ({ { "status", 200 }, { "message", "success" }, { "extended", true } }));
471 expectDeepEqual (ToVar::convert (TypeWithRawVarLast { 200,
472 "success",
473 JSONUtils::makeObject ({ { "status", 123.456 },
474 { "message", "failure" },
475 { "extended", true } }) }),
476 JSONUtils::makeObject ({ { "status", 200 },
477 { "message", "success" },
478 { "extended", JSONUtils::makeObject ({ { "status", 123.456 },
479 { "message", "failure" },
480 { "extended", true } }) } }));
481
482 expectDeepEqual (ToVar::convert (TypeWithRawVarFirst { 200, "success", true }),
483 JSONUtils::makeObject ({ { "status", 200 }, { "message", "success" }, { "extended", true } }));
484 expectDeepEqual (ToVar::convert (TypeWithRawVarFirst { 200,
485 "success",
486 JSONUtils::makeObject ({ { "status", 123.456 },
487 { "message", "failure" },
488 { "extended", true } }) }),
489 JSONUtils::makeObject ({ { "status", 200 },
490 { "message", "success" },
491 { "extended", JSONUtils::makeObject ({ { "status", 123.456 },
492 { "message", "failure" },
493 { "extended", true } }) } }));
494
495 const auto payload = JSONUtils::makeObject ({ { "foo", 1 }, { "bar", 2 } });
496 expectDeepEqual (ToVar::convert (TypeWithInnerVar { 404, payload }),
497 JSONUtils::makeObject ({ { "eventId", 404 }, { "payload", payload } }));
498 }
499
500 beginTest ("FromVar");
501 {
502 expect (FromVar::convert<bool> (JSON::fromString ("false")) == false);
503 expect (FromVar::convert<bool> (JSON::fromString ("true")) == true);
504 expect (FromVar::convert<bool> (JSON::fromString ("0")) == false);
505 expect (FromVar::convert<bool> (JSON::fromString ("1")) == true);
506 expect (FromVar::convert<int> (JSON::fromString ("1")) == 1);
507 expect (FromVar::convert<float> (JSON::fromString ("5.0f")) == 5.0f);
508 expect (FromVar::convert<int64> (JSON::fromString ("6")) == 6);
509 expect (FromVar::convert<String> (JSON::fromString ("\"hello world\"")) == "hello world");
510 expect (FromVar::convert<std::vector<int>> (JSON::fromString ("[1,2,3]")) == std::vector<int> { 1, 2, 3 });
511 expect (FromVar::convert<TypeWithExternalUnifiedSerialisation> (JSONUtils::makeObject ({ { "__version__", 2 },
512 { "a", 7 },
513 { "b", "hello world" },
514 { "c", Array<var> { 5, 6, 7 } },
515 { "d",
516 Array<var> { JSONUtils::makeObject ({ { "first", "bar" },
517 { "second", 5 } }),
518 JSONUtils::makeObject ({ { "first", "foo" },
519 { "second", 4 } }) } } }))
520 == TypeWithExternalUnifiedSerialisation { 7,
521 "hello world",
522 { 5, 6, 7 },
523 { { "foo", 4 }, { "bar", 5 } } });
524
525 expect (FromVar::convert<TypeWithInternalUnifiedSerialisation> (JSONUtils::makeObject ({ { "__version__", 5 },
526 { "a", 7.89 },
527 { "b", 4.321f },
528 { "c", "custom string" },
529 { "d", Array<var> { "foo", "bar", "baz" } } }))
530 == TypeWithInternalUnifiedSerialisation { 7.89,
531 4.321f,
532 "custom string",
533 { "foo", "bar", "baz" } });
534
535 expect (FromVar::convert<TypeWithExternalSplitSerialisation> (JSONUtils::makeObject ({ { "__version__", 10 },
536 { "a", JSONUtils::makeObject ({ { "engaged", true }, { "value", "string" } }) },
537 { "b", Array<var> { "0x1", "0x2", "0x3" } } }))
538 == TypeWithExternalSplitSerialisation { "string", { 1, 2, 3 } });
539 expect (FromVar::convert<TypeWithInternalSplitSerialisation> (JSONUtils::makeObject ({ { "__version__", 1 },
540 { "a", "string" },
541 { "b", Array<var> { "0x10", "0x20", "0x30" } } }))
542 == TypeWithInternalSplitSerialisation { "string", { 16, 32, 48 } });
543
544 expect (FromVar::convert<TypeWithBrokenObjectSerialisation> (JSON::fromString ("null")) == std::nullopt);
545 expect (FromVar::convert<TypeWithBrokenPrimitiveSerialisation> (JSON::fromString ("null")) == std::nullopt);
546 expect (FromVar::convert<TypeWithBrokenArraySerialisation> (JSON::fromString ("null")) == std::nullopt);
547 expect (FromVar::convert<TypeWithBrokenNestedSerialisation> (JSON::fromString ("null")) == std::nullopt);
548 expect (FromVar::convert<TypeWithBrokenDynamicSerialisation> (JSON::fromString ("null")) == std::nullopt);
549
550 expect (FromVar::convert<TypeWithInternalUnifiedSerialisation> (JSONUtils::makeObject ({ { "a", 7.89 },
551 { "b", 4.321f } }))
552 == std::nullopt);
553
554 expect (FromVar::convert<TypeWithVersionedSerialisation> (JSONUtils::makeObject ({ { "__version__", 3 },
555 { "a", 1 },
556 { "b", 2 },
557 { "c", 3 },
558 { "d", 4 } }))
559 == TypeWithVersionedSerialisation { 1, 2, 3, 4 });
560 expect (FromVar::convert<TypeWithVersionedSerialisation> (JSONUtils::makeObject ({ { "__version__", 4 },
561 { "a", 1 },
562 { "b", 2 },
563 { "c", 3 },
564 { "d", 4 } }))
565 == TypeWithVersionedSerialisation { 1, 2, 3, 4 });
566 expect (FromVar::convert<TypeWithVersionedSerialisation> (JSONUtils::makeObject ({ { "__version__", 2 },
567 { "a", 1 },
568 { "b", 2 },
569 { "c", 3 } }))
570 == TypeWithVersionedSerialisation { 1, 2, 3, 0 });
571 expect (FromVar::convert<TypeWithVersionedSerialisation> (JSONUtils::makeObject ({ { "__version__", 1 },
572 { "a", 1 },
573 { "b", 2 } }))
574 == TypeWithVersionedSerialisation { 1, 2, 0, 0 });
575 expect (FromVar::convert<TypeWithVersionedSerialisation> (JSONUtils::makeObject ({ { "__version__", 0 },
576 { "a", 1 } }))
577 == TypeWithVersionedSerialisation { 1, 0, 0, 0 });
578 expect (FromVar::convert<TypeWithVersionedSerialisation> (JSONUtils::makeObject ({ { "a", 1 } }))
579 == TypeWithVersionedSerialisation { 1, 0, 0, 0 });
580
581 const auto raw = JSONUtils::makeObject ({ { "status", 200 }, { "message", "success" }, { "extended", "another string" } });
582 expect (FromVar::convert<TypeWithRawVarLast> (raw) == TypeWithRawVarLast { 200, "success", "another string" });
583 expect (FromVar::convert<TypeWithRawVarFirst> (raw) == TypeWithRawVarFirst { 200, "success", "another string" });
584
585 const var payloads[] { JSONUtils::makeObject ({ { "foo", 1 }, { "bar", 2 } }),
586 var (Array<var> { 1, 2 }),
587 var() };
588
589 for (const auto& payload : payloads)
590 {
591 const auto objectWithPayload = JSONUtils::makeObject ({ { "eventId", 404 }, { "payload", payload } });
592 expect (FromVar::convert<TypeWithInnerVar> (objectWithPayload) == TypeWithInnerVar { 404, payload });
593 }
594 }
595 }
596
597private:
598 void expectDeepEqual (const std::optional<var>& a, const std::optional<var>& b)
599 {
600 const auto text = a.has_value() && b.has_value()
601 ? JSON::toString (*a) + " != " + JSON::toString (*b)
602 : String();
603 expect (deepEqual (a, b), text);
604 }
605
606 static bool deepEqual (const std::optional<var>& a, const std::optional<var>& b)
607 {
608 if (a.has_value() && b.has_value())
609 return JSONUtils::deepEqual (*a, *b);
610
611 return a == b;
612 }
613};
614
615static JSONSerialisationTest jsonSerialisationTest;
616
617} // namespace juce
static std::optional< T > convert(const var &v)
static var fromString(StringRef)
Definition: juce_JSON.cpp:478
static String toString(const var &objectToFormat, bool allOnOneLine=false, int maximumDecimalPlaces=15)
Definition: juce_JSON.cpp:513
static String toHexString(IntegerType number)
Definition: juce_String.h:1097
static std::optional< var > convert(const T &t, const Options &options={})
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
void expect(bool testResult, const String &failureMessage=String())
static bool deepEqual(const var &a, const var &b)
static var makeObject(const std::map< Identifier, var > &source)