OpenShot Audio Library | OpenShotAudio  0.6.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 
23 namespace juce
24 {
25 
26 struct 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 
42 template <>
43 struct 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
58 static_assert (detail::serialisationKind<TypeWithExternalUnifiedSerialisation> == detail::SerialisationKind::external);
59 
60 struct 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 
87 static_assert (detail::serialisationKind<TypeWithInternalUnifiedSerialisation> == detail::SerialisationKind::internal);
88 
89 struct 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 
103 template <>
104 struct 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
136 static_assert (detail::serialisationKind<TypeWithExternalSplitSerialisation> == detail::SerialisationKind::external);
137 
138 // Check that serialisation kinds are correctly detected for primitives
139 static_assert (detail::serialisationKind<bool> == detail::SerialisationKind::primitive);
140 static_assert (detail::serialisationKind< int8_t> == detail::SerialisationKind::primitive);
141 static_assert (detail::serialisationKind< uint8_t> == detail::SerialisationKind::primitive);
142 static_assert (detail::serialisationKind< int16_t> == detail::SerialisationKind::primitive);
143 static_assert (detail::serialisationKind<uint16_t> == detail::SerialisationKind::primitive);
144 static_assert (detail::serialisationKind< int32_t> == detail::SerialisationKind::primitive);
145 static_assert (detail::serialisationKind<uint32_t> == detail::SerialisationKind::primitive);
146 static_assert (detail::serialisationKind< int64_t> == detail::SerialisationKind::primitive);
147 static_assert (detail::serialisationKind<uint64_t> == detail::SerialisationKind::primitive);
148 static_assert (detail::serialisationKind<float> == detail::SerialisationKind::primitive);
149 static_assert (detail::serialisationKind<double> == detail::SerialisationKind::primitive);
150 static_assert (detail::serialisationKind<std::byte> == detail::SerialisationKind::primitive);
151 static_assert (detail::serialisationKind<String> == detail::SerialisationKind::primitive);
152 
153 // Check that serialisation is disabled for types with no serialsation defined
154 static_assert (detail::serialisationKind<Logger> == detail::SerialisationKind::none);
155 static_assert (detail::serialisationKind<CriticalSection> == detail::SerialisationKind::none);
156 
157 struct 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 
199 static_assert (detail::serialisationKind<TypeWithInternalSplitSerialisation> == detail::SerialisationKind::internal);
200 
201 struct 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 
218 struct 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 
235 struct 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 
250 struct 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 
264 struct 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 
277 struct 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 
307 struct 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 
332 struct 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 
357 struct 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 
380 class JSONSerialisationTest final : public UnitTest
381 {
382 public:
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 
597 private:
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 
615 static 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)