56b6e5b9f6
Closes https://github.com/dart-lang/sdk/pull/59581 GitOrigin-RevId: 8137077107f7f566213b8f09ddfc6610c194367a Change-Id: I263a189a6ec181fa8a6e28d77efe20d0cec0629b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/396629 Reviewed-by: Jake Macdonald <jakemac@google.com> Commit-Queue: Jake Macdonald <jakemac@google.com>
462 lines
13 KiB
Dart
462 lines
13 KiB
Dart
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
//
|
|
// SharedOptions=--enable-experiment=macros
|
|
|
|
import 'package:json/json.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
void main() {
|
|
group('Can encode and decode', () {
|
|
test('non-nullable fields', () {
|
|
var json = {
|
|
'boolField': true,
|
|
'stringField': 'hello',
|
|
'intField': 10,
|
|
'doubleField': 12.5,
|
|
'numField': 11,
|
|
'dateTimeField': '2024-11-11T03:42:29.108308',
|
|
'listOfSerializableField': [
|
|
{'x': 1},
|
|
],
|
|
'setOfSerializableField': [
|
|
{'x': 2},
|
|
],
|
|
'mapOfSerializableField': {
|
|
'c': {'x': 3}
|
|
},
|
|
'customStringSerializationField': 'hi',
|
|
'customNullableStringSerialization': null,
|
|
'customMapSerializationField': {
|
|
'z': 'zzz',
|
|
}
|
|
};
|
|
|
|
var a = A.fromJson(json);
|
|
expect(a.boolField, true);
|
|
expect(a.stringField, 'hello');
|
|
expect(a.intField, 10);
|
|
expect(a.doubleField, 12.5);
|
|
expect(a.numField, 11);
|
|
expect(a.dateTimeField, DateTime.parse('2024-11-11T03:42:29.108308'));
|
|
expect(a.listOfSerializableField.single.x, 1);
|
|
expect(a.setOfSerializableField.single.x, 2);
|
|
expect(a.mapOfSerializableField['c']!.x, 3);
|
|
expect(a.customStringSerializationField, CustomStringSerialization('hi'));
|
|
expect(a.customNullableStringSerialization,
|
|
equals(CustomNullableStringSerialization(null)));
|
|
expect(
|
|
a.customMapSerializationField, CustomMapSerialization({'z': 'zzz'}));
|
|
|
|
expect(a.toJson(), equals(json));
|
|
});
|
|
|
|
test('nullable fields with non-null values', () {
|
|
var json = {
|
|
'nullableBoolField': false,
|
|
'nullableStringField': 'world',
|
|
'nullableIntField': 9,
|
|
'nullableDoubleField': 11.5,
|
|
'nullableNumField': 11.1,
|
|
'nullableDateTimeField': '2024-11-11T03:42:29.108308',
|
|
'nullableListOfSerializableField': [
|
|
{'x': 1},
|
|
],
|
|
'nullableSetOfSerializableField': [
|
|
{'x': 2},
|
|
],
|
|
'nullableMapOfSerializableField': {
|
|
'd': {'x': 3},
|
|
},
|
|
'nullableCustomStringSerializationField': 'hi',
|
|
'nullableCustomMapSerializationField': {'z': 'zzz'},
|
|
};
|
|
|
|
var b = B.fromJson(json);
|
|
expect(b.nullableBoolField, false);
|
|
expect(b.nullableStringField, 'world');
|
|
expect(b.nullableIntField, 9);
|
|
expect(b.nullableDoubleField, 11.5);
|
|
expect(b.nullableNumField, 11.1);
|
|
expect(b.nullableDateTimeField,
|
|
DateTime.parse('2024-11-11T03:42:29.108308'));
|
|
expect(b.nullableListOfSerializableField!.single.x, 1);
|
|
expect(b.nullableSetOfSerializableField!.single.x, 2);
|
|
expect(b.nullableMapOfSerializableField!['d']!.x, 3);
|
|
expect(b.nullableCustomStringSerializationField,
|
|
CustomStringSerialization('hi'));
|
|
expect(b.nullableCustomMapSerializationField,
|
|
CustomMapSerialization({'z': 'zzz'}));
|
|
|
|
expect(b.toJson(), equals(json));
|
|
});
|
|
|
|
test('nullable fields with explicit null values', () {
|
|
var b = B.fromJson({
|
|
'nullableBoolField': null,
|
|
'nullableStringField': null,
|
|
'nullableIntField': null,
|
|
'nullableDoubleField': null,
|
|
'nullableNumField': null,
|
|
'nullableDateTimeField': null,
|
|
'nullableListOfSerializableField': null,
|
|
'nullableSetOfSerializableField': null,
|
|
'nullableMapOfSerializableField': null,
|
|
'nullableCustomStringSerializationField': null,
|
|
'nullableCustomMapSerializationField': null,
|
|
});
|
|
expect(b.nullableBoolField, null);
|
|
expect(b.nullableStringField, null);
|
|
expect(b.nullableIntField, null);
|
|
expect(b.nullableDoubleField, null);
|
|
expect(b.nullableNumField, null);
|
|
expect(b.nullableDateTimeField, null);
|
|
expect(b.nullableListOfSerializableField, null);
|
|
expect(b.nullableMapOfSerializableField, null);
|
|
expect(b.nullableSetOfSerializableField, null);
|
|
expect(b.nullableCustomStringSerializationField, null);
|
|
expect(b.nullableCustomMapSerializationField, null);
|
|
|
|
expect(b.toJson(), isEmpty);
|
|
});
|
|
|
|
test('nullable fields with missing values', () {
|
|
var b = B.fromJson({});
|
|
expect(b.nullableBoolField, null);
|
|
expect(b.nullableStringField, null);
|
|
expect(b.nullableIntField, null);
|
|
expect(b.nullableDoubleField, null);
|
|
expect(b.nullableNumField, null);
|
|
expect(b.nullableDateTimeField, null);
|
|
expect(b.nullableListOfSerializableField, null);
|
|
expect(b.nullableMapOfSerializableField, null);
|
|
expect(b.nullableSetOfSerializableField, null);
|
|
expect(b.nullableCustomStringSerializationField, null);
|
|
expect(b.nullableCustomMapSerializationField, null);
|
|
|
|
expect(b.toJson(), isEmpty);
|
|
});
|
|
|
|
test('class hierarchies', () {
|
|
var json = {
|
|
'x': 1,
|
|
'y': 'z',
|
|
};
|
|
var d = D.fromJson(json);
|
|
expect(d.x, 1);
|
|
expect(d.y, 'z');
|
|
|
|
expect(d.toJson(), equals(json));
|
|
});
|
|
|
|
test('collections of nullable objects', () {
|
|
var json = {
|
|
'listOfNullableDates': [null, '2024-11-11T03:42:29.108308'],
|
|
'listOfNullableInts': [null, 1],
|
|
'listOfNullableSerializables': [
|
|
{'x': 1},
|
|
null
|
|
],
|
|
'listOfNullableMapsOfNullableInts': [
|
|
null,
|
|
{'a': 1, 'b': null},
|
|
],
|
|
'listOfCustomStringSerializables': [null, 'hi'],
|
|
'listOfCustomMapSerializables': [
|
|
null,
|
|
{'z': 'zzz'},
|
|
],
|
|
'setOfNullableDates': [
|
|
null,
|
|
'2024-11-12T03:42:29.108308',
|
|
],
|
|
'setOfNullableInts': [
|
|
null,
|
|
2,
|
|
],
|
|
'setOfNullableSerializables': [
|
|
{'x': 2},
|
|
null,
|
|
],
|
|
'setOfNullableMapsOfNullableInts': [
|
|
null,
|
|
{
|
|
'a': 2,
|
|
'b': null,
|
|
},
|
|
],
|
|
'setOfCustomStringSerializables': [null, 'hi'],
|
|
'setOfCustomMapSerializables': [
|
|
null,
|
|
{'z': 'zzz'}
|
|
],
|
|
'mapOfNullableDates': {
|
|
'a': '2024-11-13T03:42:29.108308',
|
|
'b': null,
|
|
},
|
|
'mapOfNullableInts': {
|
|
'a': 3,
|
|
'b': null,
|
|
},
|
|
'mapOfNullableSerializables': {
|
|
'a': {'x': 3},
|
|
'b': null
|
|
},
|
|
'mapOfNullableSetsOfNullableInts': {
|
|
'a': [null, 3],
|
|
'b': null,
|
|
},
|
|
'mapOfCustomStringSerializables': {
|
|
'a': null,
|
|
'b': 'hi',
|
|
},
|
|
'mapOfCustomMapSerializables': {
|
|
'a': null,
|
|
'b': {'z': 'zzz'},
|
|
},
|
|
};
|
|
|
|
var e = E.fromJson(json);
|
|
expect(e.listOfNullableDates,
|
|
equals([null, DateTime.parse('2024-11-11T03:42:29.108308')]));
|
|
expect(e.listOfNullableInts, equals([null, 1]));
|
|
expect(e.listOfNullableSerializables.first!.x, 1);
|
|
expect(e.listOfNullableSerializables[1], null);
|
|
expect(
|
|
e.listOfNullableMapsOfNullableInts,
|
|
equals([
|
|
null,
|
|
{'a': 1, 'b': null},
|
|
]));
|
|
expect(e.listOfCustomStringSerializables.first, null);
|
|
expect(e.listOfCustomStringSerializables[1],
|
|
CustomStringSerialization('hi'));
|
|
expect(e.listOfCustomMapSerializables.first, null);
|
|
expect(e.listOfCustomMapSerializables[1],
|
|
CustomMapSerialization({'z': 'zzz'}));
|
|
|
|
expect(e.setOfNullableDates,
|
|
equals([null, DateTime.parse('2024-11-12T03:42:29.108308')]));
|
|
expect(e.setOfNullableInts, equals({null, 2}));
|
|
expect(e.setOfNullableSerializables.first!.x, 2);
|
|
expect(e.setOfNullableSerializables.elementAt(1), null);
|
|
expect(
|
|
e.setOfNullableMapsOfNullableInts,
|
|
equals({
|
|
null,
|
|
{
|
|
'a': 2,
|
|
'b': null,
|
|
},
|
|
}));
|
|
expect(e.setOfCustomStringSerializables.first, null);
|
|
expect(e.setOfCustomStringSerializables.toList()[1],
|
|
CustomStringSerialization('hi'));
|
|
expect(e.setOfCustomMapSerializables.first, null);
|
|
expect(e.setOfCustomMapSerializables.toList()[1],
|
|
CustomMapSerialization({'z': 'zzz'}));
|
|
|
|
expect(
|
|
e.mapOfNullableDates,
|
|
equals({
|
|
'a': DateTime.parse('2024-11-13T03:42:29.108308'),
|
|
'b': null,
|
|
}));
|
|
expect(
|
|
e.mapOfNullableInts,
|
|
equals({
|
|
'a': 3,
|
|
'b': null,
|
|
}));
|
|
expect(e.mapOfNullableSerializables['a']!.x, 3);
|
|
expect(e.mapOfNullableSerializables.containsKey('b'), true);
|
|
expect(e.mapOfNullableSerializables['b'], null);
|
|
expect(e.mapOfNullableSetsOfNullableInts, {
|
|
'a': {null, 3},
|
|
'b': null,
|
|
});
|
|
expect(e.mapOfCustomStringSerializables['a'], null);
|
|
expect(e.mapOfCustomStringSerializables['b'],
|
|
CustomStringSerialization('hi'));
|
|
expect(e.mapOfCustomMapSerializables['a'], null);
|
|
expect(e.mapOfCustomMapSerializables['b'],
|
|
CustomMapSerialization({'z': 'zzz'}));
|
|
|
|
expect(e.toJson(), equals(json));
|
|
});
|
|
|
|
test(r'field with dollar sign $', () {
|
|
var json = {
|
|
r'fieldWithDollarSign$': 1,
|
|
};
|
|
var f = F.fromJson(json);
|
|
expect(f.fieldWithDollarSign$, 1);
|
|
|
|
expect(f.toJson(), equals(json));
|
|
});
|
|
});
|
|
}
|
|
|
|
@JsonCodable()
|
|
class A {
|
|
final bool boolField;
|
|
|
|
final String stringField;
|
|
|
|
final int intField;
|
|
|
|
final double doubleField;
|
|
|
|
final num numField;
|
|
|
|
final DateTime dateTimeField;
|
|
|
|
final List<C> listOfSerializableField;
|
|
|
|
final Set<C> setOfSerializableField;
|
|
|
|
final Map<String, C> mapOfSerializableField;
|
|
|
|
final CustomStringSerialization customStringSerializationField;
|
|
|
|
final CustomMapSerialization customMapSerializationField;
|
|
|
|
final CustomNullableStringSerialization customNullableStringSerialization;
|
|
}
|
|
|
|
@JsonCodable()
|
|
class B {
|
|
final bool? nullableBoolField;
|
|
|
|
final String? nullableStringField;
|
|
|
|
final int? nullableIntField;
|
|
|
|
final double? nullableDoubleField;
|
|
|
|
final num? nullableNumField;
|
|
|
|
final DateTime? nullableDateTimeField;
|
|
|
|
final List<C>? nullableListOfSerializableField;
|
|
|
|
final Set<C>? nullableSetOfSerializableField;
|
|
|
|
final Map<String, C>? nullableMapOfSerializableField;
|
|
|
|
final CustomStringSerialization? nullableCustomStringSerializationField;
|
|
|
|
final CustomMapSerialization? nullableCustomMapSerializationField;
|
|
}
|
|
|
|
@JsonCodable()
|
|
class C {
|
|
final int x;
|
|
}
|
|
|
|
@JsonCodable()
|
|
class D extends C {
|
|
final String y;
|
|
}
|
|
|
|
@JsonCodable()
|
|
class E {
|
|
final List<DateTime?> listOfNullableDates;
|
|
|
|
final List<int?> listOfNullableInts;
|
|
|
|
final List<C?> listOfNullableSerializables;
|
|
|
|
final List<Map<String, int?>?> listOfNullableMapsOfNullableInts;
|
|
|
|
final List<CustomStringSerialization?> listOfCustomStringSerializables;
|
|
|
|
final List<CustomMapSerialization?> listOfCustomMapSerializables;
|
|
|
|
final Set<DateTime?> setOfNullableDates;
|
|
|
|
final Set<int?> setOfNullableInts;
|
|
|
|
final Set<C?> setOfNullableSerializables;
|
|
|
|
final Set<Map<String, int?>?> setOfNullableMapsOfNullableInts;
|
|
|
|
final Set<CustomStringSerialization?> setOfCustomStringSerializables;
|
|
|
|
final Set<CustomMapSerialization?> setOfCustomMapSerializables;
|
|
|
|
final Map<String, DateTime?> mapOfNullableDates;
|
|
|
|
final Map<String, int?> mapOfNullableInts;
|
|
|
|
final Map<String, C?> mapOfNullableSerializables;
|
|
|
|
final Map<String, Set<int?>?> mapOfNullableSetsOfNullableInts;
|
|
|
|
final Map<String, CustomStringSerialization?> mapOfCustomStringSerializables;
|
|
|
|
final Map<String, CustomMapSerialization?> mapOfCustomMapSerializables;
|
|
}
|
|
|
|
@JsonCodable()
|
|
class F {
|
|
final int fieldWithDollarSign$;
|
|
}
|
|
|
|
class CustomStringSerialization {
|
|
final String a;
|
|
|
|
CustomStringSerialization(this.a);
|
|
|
|
String toJson() => a;
|
|
|
|
factory CustomStringSerialization.fromJson(String a) =>
|
|
CustomStringSerialization(a);
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
other is CustomStringSerialization && a == other.a;
|
|
|
|
@override
|
|
int get hashCode => a.hashCode;
|
|
}
|
|
|
|
class CustomNullableStringSerialization {
|
|
final String? a;
|
|
|
|
CustomNullableStringSerialization(this.a);
|
|
|
|
String? toJson() => a;
|
|
|
|
factory CustomNullableStringSerialization.fromJson(String? a) =>
|
|
CustomNullableStringSerialization(a);
|
|
|
|
@override
|
|
bool operator ==(Object other) =>
|
|
other is CustomNullableStringSerialization && a == other.a;
|
|
|
|
@override
|
|
int get hashCode => a.hashCode;
|
|
}
|
|
|
|
class CustomMapSerialization {
|
|
final Map<String, dynamic> a;
|
|
|
|
CustomMapSerialization(this.a);
|
|
|
|
Map<String, dynamic> toJson() => a;
|
|
|
|
factory CustomMapSerialization.fromJson(Map<String, dynamic> a) =>
|
|
CustomMapSerialization(a);
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return other is CustomMapSerialization &&
|
|
a.toString() == other.a.toString();
|
|
}
|
|
|
|
@override
|
|
int get hashCode => a.hashCode;
|
|
}
|