diff --git a/lib/features/recording/model/model_clipboard.dart b/lib/features/recording/model/model_clipboard.dart index 915c349..c0a92f4 100644 --- a/lib/features/recording/model/model_clipboard.dart +++ b/lib/features/recording/model/model_clipboard.dart @@ -19,8 +19,8 @@ class ClipboardRecordingModel { factory ClipboardRecordingModel.fromJson(Map json) { return ClipboardRecordingModel( title: _readString(json, 'title'), - startTimestamp: _readInt(json, 'startTimestamp'), - endTimestamp: _readInt(json, 'endTimestamp'), + startTimestamp: _readOptionalInt(json, 'startTimestamp'), + endTimestamp: _readOptionalInt(json, 'endTimestamp'), address: _readString(json, 'address'), filename: _readOptionalString(json, 'filename'), ); @@ -52,8 +52,9 @@ class ClipboardRecordingModel { throw FormatException('Clipboard field "$key" must be a String.'); } - static int _readInt(Map json, String key) { + static int? _readOptionalInt(Map json, String key) { final value = json[key]; + if (value == null) return null; if (value is int) return value; throw FormatException('Clipboard field "$key" must be an int.'); } diff --git a/lib/features/recording/view-model/view_model_recording.dart b/lib/features/recording/view-model/view_model_recording.dart index 66debce..b30a1dc 100644 --- a/lib/features/recording/view-model/view_model_recording.dart +++ b/lib/features/recording/view-model/view_model_recording.dart @@ -30,8 +30,6 @@ class RecordingViewModel extends StateNotifier { RecordingModel( clipboardRecordingModel: ClipboardRecordingModel( title: '', - startTimestamp: 0, - endTimestamp: 0, address: '', ), ), @@ -40,8 +38,6 @@ class RecordingViewModel extends StateNotifier { static final _defaultClipboard = ClipboardRecordingModel( title: '', - startTimestamp: 0, - endTimestamp: 0, address: '', ); diff --git a/test/features/recording/model_clipboard_test.dart b/test/features/recording/model_clipboard_test.dart index 7bb652b..5d3e674 100644 --- a/test/features/recording/model_clipboard_test.dart +++ b/test/features/recording/model_clipboard_test.dart @@ -21,6 +21,21 @@ void main() { expect(model.toJson(), clipboardJson); }); + test('parses JSON without optional timestamps', () { + final json = { + 'title': '郑昌梦 丨黄伟依 空中格斗赛 小学组', + 'address': '广东省汕头市番禺区青蓝街 111 号', + 'filename': '郑昌梦_黄伟依_6月3日测试-1_空中格斗赛', + }; + final model = ClipboardRecordingModel.fromJson(json); + + expect(model.title, json['title']); + expect(model.address, json['address']); + expect(model.filename, json['filename']); + expect(model.startTimestamp, isNull); + expect(model.endTimestamp, isNull); + }); + test('parses optional filename from mini program JSON', () { final json = { ...clipboardJson, @@ -41,7 +56,7 @@ void main() { ); }); - test('throws FormatException when required field has wrong type', () { + test('throws FormatException when optional int field has wrong type', () { final json = {...clipboardJson, 'startTimestamp': '1717334400'}; expect( @@ -49,5 +64,14 @@ void main() { throwsA(isA()), ); }); + + test('throws FormatException when required address is missing', () { + final json = Map.from(clipboardJson)..remove('address'); + + expect( + () => ClipboardRecordingModel.fromJson(json), + throwsA(isA()), + ); + }); }); } diff --git a/test/features/recording/view_model_recording_test.dart b/test/features/recording/view_model_recording_test.dart index 557c684..bee487a 100644 --- a/test/features/recording/view_model_recording_test.dart +++ b/test/features/recording/view_model_recording_test.dart @@ -105,7 +105,7 @@ void main() { ); }); - test('returns invalid when clipboard JSON misses required fields', () async { + test('returns invalid when clipboard JSON misses required address', () async { await setClipboardText('{"title":"王东方 丨李想 空中格斗赛"}'); final container = ProviderContainer(); addTearDown(container.dispose); @@ -121,6 +121,31 @@ void main() { ); }); + test( + 'updates state when clipboard omits optional timestamps', + () async { + await setClipboardText( + '{"title":"郑昌梦 丨黄伟依 空中格斗赛 小学组","address":"广东省汕头市番禺区青蓝街 111 号","filename":"郑昌梦_黄伟依_6月3日测试-1_空中格斗赛"}', + ); + final container = ProviderContainer(); + addTearDown(container.dispose); + + final result = await container + .read(recordingViewModelProvider.notifier) + .getClipboardContent(); + + expect(result, ClipboardReadResult.success); + final model = container.read(recordingViewModelProvider); + expect(model.hasValidClipboardInfo, isTrue); + expect(model.clipboardRecordingModel.startTimestamp, isNull); + expect(model.clipboardRecordingModel.endTimestamp, isNull); + expect( + model.clipboardRecordingModel.filename, + '郑昌梦_黄伟依_6月3日测试-1_空中格斗赛', + ); + }, + ); + test('returns invalid when clipboard JSON has wrong field type', () async { await setClipboardText( '{"title":"王东方 丨李想 空中格斗赛","startTimestamp":"1717334400","endTimestamp":1717334400,"address":"广州市番禺区·粤港澳大湾区青年人才双创小镇"}',