import 'package:flutter_test/flutter_test.dart'; import 'package:mews/application/pages/mews_urls.dart'; void main() { group('isInternal', () { test('recognizes the mews scheme only', () { expect(MewsUrls.isInternal('mews:hub'), isTrue); expect(MewsUrls.isInternal('mews:'), isTrue); expect(MewsUrls.isInternal('https://example.test/'), isFalse); expect(MewsUrls.isInternal('not a url at all'), isFalse); }); }); group('isAction', () { test('accepts exactly one verb under do/', () { expect(MewsUrls.isAction('mews:do/set-theme?value=dark'), isTrue); expect(MewsUrls.isAction('mews:do/clear-history'), isTrue); }); test('rejects pages, bare do and deeper paths', () { expect(MewsUrls.isAction('mews:settings'), isFalse); expect(MewsUrls.isAction('mews:do'), isFalse); expect(MewsUrls.isAction('mews:do/a/b'), isFalse); // A fetched page must not reach the dispatcher by mimicking the path. expect(MewsUrls.isAction('https://example.test/do/clear-history'), isFalse); }); test('verbOf reads the verb back', () { expect(MewsUrls.verbOf('mews:do/set-size?step=up'), 'set-size'); expect(MewsUrls.verbOf('mews:settings'), isNull); }); }); group('canonical', () { test('bare mews: is the hub', () { expect(MewsUrls.canonical('mews:'), MewsUrls.hub); }); test('keeps a query string and drops a fragment', () { expect(MewsUrls.canonical('mews:bookmarks?tag=phones'), 'mews:bookmarks?tag=phones'); expect(MewsUrls.canonical('mews:settings#colors'), 'mews:settings'); }); test('leaves external addresses alone', () { expect(MewsUrls.canonical('https://example.test/a?b=c'), 'https://example.test/a?b=c'); }); }); group('action', () { test('builds an address the dispatcher accepts', () { final url = MewsUrls.action('set-theme', {'value': 'dark'}); expect(url, 'mews:do/set-theme?value=dark'); expect(MewsUrls.isAction(url), isTrue); }); test('round-trips a url carried inside the query string', () { // Every per-item action names its target this way, so the inner address // must survive encoding untouched. const target = 'https://example.test/p?q=1&r=2'; final url = MewsUrls.action('remove-bookmark', {'url': target}); expect(Uri.parse(url).queryParameters['url'], target); expect(MewsUrls.isAction(url), isTrue); }); test('takes no query string when there are no arguments', () { expect(MewsUrls.action('clear-history'), 'mews:do/clear-history'); }); }); group('page', () { test('merges over the existing parameters', () { final url = MewsUrls.page(Uri.parse('mews:bookmarks?tag=phones'), {'q': 'retro'}); final params = Uri.parse(url).queryParameters; expect(params, {'tag': 'phones', 'q': 'retro'}); }); test('an empty value drops the parameter', () { final url = MewsUrls.page(Uri.parse('mews:bookmarks?tag=phones&q=retro'), {'q': ''}); expect(Uri.parse(url).queryParameters, {'tag': 'phones'}); }); test('drops the query string once nothing is left', () { final url = MewsUrls.page(Uri.parse('mews:bookmarks?q=retro'), {'q': ''}); expect(url, 'mews:bookmarks'); }); test('survives a value needing escapes', () { final url = MewsUrls.page(Uri.parse(MewsUrls.bookmarks), {'q': 'a b&c=d'}); expect(Uri.parse(url).queryParameters['q'], 'a b&c=d'); expect(MewsUrls.canonical(url), url); }); }); }