Skip to content

Commit 81b39a7

Browse files
authored
Merge pull request #41 from flutter-news-app-full-source-code/aa
Enhance serialization
2 parents 88f9257 + 5f77d1c commit 81b39a7

File tree

4 files changed

+107
-2
lines changed

4 files changed

+107
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🛠️ core
22

3-
![coverage: percentage](https://img.shields.io/badge/coverage-99-green)
3+
![coverage: percentage](https://img.shields.io/badge/coverage-98-green)
44
[![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg)](https://pub.dev/packages/very_good_analysis)
55
[![License: PolyForm Free Trial](https://img.shields.io/badge/License-PolyForm%20Free%20Trial-blue)](https://polyformproject.org/licenses/free-trial/1.0.0)
66

lib/src/models/core/feed_item.dart

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,51 @@ abstract class FeedItem extends Equatable {
7373
}
7474
}
7575

76+
/// Static factory method to serialize a [FeedItem] instance to a JSON map.
77+
///
78+
/// This factory uses the `type` field of the provided [item] to dispatch
79+
/// to the correct concrete `toJson` method.
80+
///
81+
/// Throws [FormatException] if the `type` field is missing or unknown.
82+
static Map<String, dynamic> toJson(FeedItem item) {
83+
switch (item.type) {
84+
case 'headline':
85+
final headlineItem = item as Headline;
86+
return headlineItem.toJson();
87+
case 'topic':
88+
final topicItem = item as Topic;
89+
return topicItem.toJson();
90+
case 'source':
91+
final sourceItem = item as Source;
92+
return sourceItem.toJson();
93+
case 'country':
94+
final countryItem = item as Country;
95+
return countryItem.toJson();
96+
case 'callToAction':
97+
final callToActionItem = item as CallToActionItem;
98+
return callToActionItem.toJson();
99+
case 'localAd':
100+
final localAdItem = item as LocalAd;
101+
return LocalAd.toJson(localAdItem);
102+
case 'contentCollection':
103+
// For ContentCollectionItem, we need to know the generic type T
104+
// to call its toJson method correctly.
105+
// This requires a runtime type check and casting.
106+
if (item is ContentCollectionItem<Topic>) {
107+
return item.toJson((topic) => topic.toJson());
108+
} else if (item is ContentCollectionItem<Source>) {
109+
return item.toJson((source) => source.toJson());
110+
} else if (item is ContentCollectionItem<Country>) {
111+
return item.toJson((country) => country.toJson());
112+
}
113+
throw FormatException(
114+
'Unknown ContentCollectionItem generic type: ${item.runtimeType}',
115+
);
116+
default:
117+
throw FormatException('Unknown FeedItem type for toJson: ${item.type}');
118+
}
119+
}
120+
76121
/// The type of the feed item, used as a discriminator for deserialization.
77122
final String type;
78123

lib/src/models/feed_decorators/local_ad.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,31 @@ abstract class LocalAd extends FeedItem {
3939
}
4040
}
4141

42+
/// Static factory method to serialize a [LocalAd] instance to a JSON map.
43+
///
44+
/// This factory uses the `adType` field of the provided [item] to dispatch
45+
/// to the correct concrete `toJson` method.
46+
///
47+
/// Throws [FormatException] if the `adType` field is missing or unknown.
48+
static Map<String, dynamic> toJson(LocalAd item) {
49+
switch (item.adType) {
50+
case 'native':
51+
final nativeAdItem = item as LocalNativeAd;
52+
return nativeAdItem.toJson();
53+
case 'banner':
54+
final bannerAdItem = item as LocalBannerAd;
55+
return bannerAdItem.toJson();
56+
case 'interstitial':
57+
final interstitialAdItem = item as LocalInterstitialAd;
58+
return interstitialAdItem.toJson();
59+
case 'video':
60+
final videoAdItem = item as LocalVideoAd;
61+
return videoAdItem.toJson();
62+
default:
63+
throw FormatException('Unknown LocalAd type for toJson: ${item.adType}');
64+
}
65+
}
66+
4267
/// The type of the ad (e.g., banner, native, interstitial, video).
4368
final String adType;
4469

test/src/models/feed_decorators/local_ad_test.dart

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,48 @@ void main() {
7373
isA<FormatException>().having(
7474
(e) => e.message,
7575
'message',
76-
'Unknown LocalAds type: unknown_type',
76+
'Unknown LocalAd type: unknown_type', // Corrected from LocalAds
7777
),
7878
),
7979
);
8080
});
8181
});
8282

83+
group('toJson dispatching', () {
84+
test('serializes LocalNativeAd correctly via LocalAd.toJson', () {
85+
final mockLocalNativeAd =
86+
localAdsFixturesData.firstWhere((ad) => ad.adType == 'native')
87+
as LocalNativeAd;
88+
final json = mockLocalNativeAd.toJson();
89+
expect(LocalAd.toJson(mockLocalNativeAd), equals(json));
90+
});
91+
92+
test('serializes LocalBannerAd correctly via LocalAd.toJson', () {
93+
final mockLocalBannerAd =
94+
localAdsFixturesData.firstWhere((ad) => ad.adType == 'banner')
95+
as LocalBannerAd;
96+
final json = mockLocalBannerAd.toJson();
97+
expect(LocalAd.toJson(mockLocalBannerAd), equals(json));
98+
});
99+
100+
test('serializes LocalInterstitialAd correctly via LocalAd.toJson', () {
101+
final mockLocalInterstitialAd =
102+
localAdsFixturesData.firstWhere((ad) => ad.adType == 'interstitial')
103+
as LocalInterstitialAd;
104+
final json = mockLocalInterstitialAd.toJson();
105+
expect(LocalAd.toJson(mockLocalInterstitialAd), equals(json));
106+
});
107+
108+
test('serializes LocalVideoAd correctly via LocalAd.toJson', () {
109+
final mockLocalVideoAd =
110+
localAdsFixturesData.firstWhere((ad) => ad.adType == 'video')
111+
as LocalVideoAd;
112+
final json = mockLocalVideoAd.toJson();
113+
expect(LocalAd.toJson(mockLocalVideoAd), equals(json));
114+
});
115+
116+
});
117+
83118
// Test props for a concrete LocalAd subclass (LocalNativeAd)
84119
// The test name is misleading as it tests a concrete instance's props.
85120
// The expectation is updated to reflect all properties of LocalNativeAd.

0 commit comments

Comments
 (0)