feat: add NewsItem and BriefingFeed models with tests

This commit is contained in:
2026-04-06 08:13:06 -04:00
parent a2fc0d6c7d
commit 77fc82af45
3 changed files with 127 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
class BriefingFeed {
final int id;
final String title;
final String url;
final String? category;
const BriefingFeed({
required this.id,
required this.title,
required this.url,
this.category,
});
factory BriefingFeed.fromJson(Map<String, dynamic> json) => BriefingFeed(
id: json['id'] as int,
title: json['title'] as String? ?? '',
url: json['url'] as String? ?? '',
category: json['category'] as String?,
);
}
+37
View File
@@ -0,0 +1,37 @@
class NewsItem {
final int id;
final String title;
final String url;
final String snippet;
final String source;
final DateTime? publishedAt;
final List<String> topics;
final String? reaction;
const NewsItem({
required this.id,
required this.title,
required this.url,
required this.snippet,
required this.source,
this.publishedAt,
required this.topics,
this.reaction,
});
factory NewsItem.fromJson(Map<String, dynamic> json) => NewsItem(
id: json['id'] as int,
title: json['title'] as String? ?? '',
url: json['url'] as String? ?? '',
snippet: json['snippet'] as String? ?? '',
source: json['source'] as String? ?? '',
publishedAt: json['published_at'] != null
? DateTime.tryParse(json['published_at'] as String)
: null,
topics: (json['topics'] as List<dynamic>?)
?.cast<String>()
.toList() ??
[],
reaction: json['reaction'] as String?,
);
}
+70
View File
@@ -2,6 +2,8 @@ import 'package:fabled_app/data/api/voice_api.dart';
import 'package:fabled_app/providers/voice_provider.dart';
import 'package:fabled_app/data/models/knowledge_item.dart';
import 'package:fabled_app/data/models/note.dart';
import 'package:fabled_app/data/models/news_item.dart';
import 'package:fabled_app/data/models/briefing_feed.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
@@ -146,4 +148,72 @@ void main() {
equals('item one item two'));
});
});
group('NewsItem.fromJson', () {
test('parses all fields', () {
final json = {
'id': 42,
'title': 'Big news',
'url': 'https://example.com/article',
'snippet': 'A short summary.',
'source': 'Example News',
'published_at': '2026-01-15T10:00:00',
'topics': ['tech', 'ai'],
'reaction': 'up',
};
final item = NewsItem.fromJson(json);
expect(item.id, equals(42));
expect(item.title, equals('Big news'));
expect(item.url, equals('https://example.com/article'));
expect(item.snippet, equals('A short summary.'));
expect(item.source, equals('Example News'));
expect(item.publishedAt, equals(DateTime.parse('2026-01-15T10:00:00')));
expect(item.topics, equals(['tech', 'ai']));
expect(item.reaction, equals('up'));
});
test('handles null published_at and reaction', () {
final json = {
'id': 1,
'title': '',
'url': '',
'snippet': '',
'source': '',
'published_at': null,
'topics': <dynamic>[],
'reaction': null,
};
final item = NewsItem.fromJson(json);
expect(item.publishedAt, isNull);
expect(item.reaction, isNull);
expect(item.topics, isEmpty);
});
});
group('BriefingFeed.fromJson', () {
test('parses all fields', () {
final json = {
'id': 7,
'title': 'Hacker News',
'url': 'https://news.ycombinator.com/rss',
'category': 'tech',
};
final feed = BriefingFeed.fromJson(json);
expect(feed.id, equals(7));
expect(feed.title, equals('Hacker News'));
expect(feed.url, equals('https://news.ycombinator.com/rss'));
expect(feed.category, equals('tech'));
});
test('handles null category', () {
final json = {
'id': 8,
'title': 'Feed',
'url': 'https://example.com/rss',
'category': null,
};
final feed = BriefingFeed.fromJson(json);
expect(feed.category, isNull);
});
});
}