1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
// Unit tests for json_helpers.dart.
//
// `dateTimeFromJson` is the shared deserialization helper used by every
// model that has a nullable DateTime field. These tests pin down its
// defensive contract: only well-formed ISO-8601 strings produce a
// DateTime; everything else (null, non-string, empty string, malformed
// string) silently degrades to null without throwing.
//
// The malformed-string case is the regression guard for the original
// crash bug: prior to the fix, `DateTime.parse('not a date')` propagated
// a FormatException out of fromJson() and crashed the app.
import 'package:flutter_test/flutter_test.dart';
import 'package:player_android/models/json_helpers.dart';
void main() {
group('dateTimeFromJson', () {
test('returns null for null input', () {
expect(dateTimeFromJson(null), isNull);
});
test('returns null for empty string', () {
expect(dateTimeFromJson(''), isNull);
});
test('returns null for non-string input (int)', () {
expect(dateTimeFromJson(12345), isNull);
});
test('returns null for non-string input (bool)', () {
expect(dateTimeFromJson(true), isNull);
});
test('parses a valid ISO-8601 UTC string', () {
final dt = dateTimeFromJson('2026-05-20T12:34:56.000Z');
expect(dt, isNotNull);
expect(dt!.toUtc().year, 2026);
expect(dt.toUtc().month, 5);
expect(dt.toUtc().day, 20);
expect(dt.toUtc().hour, 12);
expect(dt.toUtc().minute, 34);
expect(dt.toUtc().second, 56);
});
test('parses a valid ISO-8601 date-only string', () {
final dt = dateTimeFromJson('2026-01-15');
expect(dt, isNotNull);
expect(dt!.year, 2026);
expect(dt.month, 1);
expect(dt.day, 15);
});
test('returns null for malformed string instead of throwing', () {
// Regression guard: this used to throw FormatException and crash
// the entire model deserialization.
expect(() => dateTimeFromJson('not a date'), returnsNormally);
expect(dateTimeFromJson('not a date'), isNull);
});
test('returns null for ISO-like string with non-numeric junk', () {
// DateTime.parse is surprisingly tolerant of out-of-range numeric
// components (it rolls them over), so we use a clearly non-numeric
// value to force a FormatException.
expect(dateTimeFromJson('2026-XX-YYTzz:zz:zzZ'), isNull);
});
test('returns null for garbage tokens', () {
expect(dateTimeFromJson('@@@'), isNull);
});
});
group('dateTimeToJson', () {
test('returns null for null input', () {
expect(dateTimeToJson(null), isNull);
});
test('serializes DateTime to ISO-8601 string', () {
final dt = DateTime.utc(2026, 5, 20, 12, 34, 56);
expect(dateTimeToJson(dt), '2026-05-20T12:34:56.000Z');
});
});
}
|