import 'package:flutter_test/flutter_test.dart'; import 'package:plezy/mpv/player/mpv_node_decoder.dart'; void main() { const nestedList = [ { 'type': 'audio', 'metadata': { 'values': [true, 2, 3.5, null], }, }, ]; const nestedMap = { 'cache-end': 12.5, 'seekable-ranges': [ {'start': 1, 'end': 9.25}, ], }; final cases = <({String name, Object? input, Object? list, Object? map})>[ (name: 'nested structured list', input: nestedList, list: nestedList, map: null), (name: 'nested structured map', input: nestedMap, list: null, map: nestedMap), ( name: 'valid list JSON', input: '[{"type":"audio","metadata":{"values":[true,2,3.5,null]}}]', list: nestedList, map: null, ), ( name: 'valid map JSON', input: '{"cache-end":12.5,"seekable-ranges":[{"start":1,"end":9.25}]}', list: null, map: nestedMap, ), (name: 'malformed JSON', input: '{not-json', list: null, map: null), (name: 'JSON scalar', input: '42', list: null, map: null), (name: 'structured scalar', input: 42, list: null, map: null), (name: 'empty string', input: '', list: null, map: null), (name: 'null', input: null, list: null, map: null), (name: 'JSON null', input: 'null', list: null, map: null), (name: 'empty structured list', input: const [], list: const [], map: null), (name: 'empty structured map', input: const {}, list: null, map: const {}), (name: 'empty JSON list', input: '[]', list: const [], map: null), (name: 'empty JSON map', input: '{}', list: null, map: const {}), ]; for (final testCase in cases) { test(testCase.name, () { expect(MpvNodeDecoder.decodeList(testCase.input), testCase.list); expect(MpvNodeDecoder.decodeMap(testCase.input), testCase.map); }); } test('rejects hostile structured payloads before traversal', () { Object? acceptedDepth = 'leaf'; for (var i = 0; i < 31; i++) { acceptedDepth = [acceptedDepth]; } expect(MpvNodeDecoder.decodeList(acceptedDepth), isNotNull); Object? excessiveDepth = acceptedDepth; excessiveDepth = [excessiveDepth]; expect(MpvNodeDecoder.decodeList(excessiveDepth), isNull); expect(MpvNodeDecoder.decodeList(List.filled(16384, null)), isNull); expect(MpvNodeDecoder.decodeList([double.nan]), isNull); expect(MpvNodeDecoder.decodeMap({1: 'non-string key'}), isNull); }); test('preflights deeply nested and oversized JSON', () { final deepestAccepted = '${List.filled(31, '[').join()}null${List.filled(31, ']').join()}'; final tooDeep = '[$deepestAccepted]'; expect(MpvNodeDecoder.decodeList(deepestAccepted), isNotNull); expect(MpvNodeDecoder.decodeList(tooDeep), isNull); final tooManyEntries = '[${List.filled(16385, 'null').join(',')}]'; expect(MpvNodeDecoder.decodeList(tooManyEntries), isNull); expect(MpvNodeDecoder.decodeList('["brackets [ and braces { stay quoted"]'), isNotNull); }); }