import 'package:actors/actors.dart'; import 'package:mews/application/actors/fetch_actor.dart'; import 'package:mews/mews/atom.dart'; import 'package:mews/mews/parser.dart'; /// Serves pages from an in-memory map without network or isolates, so /// navigation tests are deterministic. [sources] wins over the cached source /// a caller offers, the way a server answering 200 does, so a test can change /// what a site publishes between two fetches. An address with no source is /// unreachable, and the cached copy stands in for it if there is one. class FakeFetch implements Actor { FakeFetch(this.sources, {this.feeds = const {}}); final Map sources; /// Atom feeds by address, for sites that publish through one. final Map feeds; @override Future send(FetchCommand message) async { return switch (message) { ParseSource(:final url, :final source) => _parse(url, source), FetchPage(:final url, :final cachedSource) => switch (( sources[url], cachedSource, )) { (final String fresh, _) => _parse(url, fresh), (null, final String cached) => _parse(url, cached), _ => const FetchNetworkError(), }, FetchFeed(:final url) => switch (feeds[url]) { final String source => FetchFeedOk(url: url, entries: parseAtomEntries(source: source, feedUrl: url)), null => const FetchNetworkError(), }, _ => const FetchNetworkError(), }; } FetchResult _parse(String url, String source) { try { return FetchPageOk(page: parseMewsPage(source: source, url: url), source: source); } on MewsParseException catch (e) { return FetchParseError(e.message, source); } } @override Future close() async {} @override dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); }