import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:halkyon_app/halkyon_app.dart'; import 'package:halkyon_app/testing.dart'; import 'package:path/path.dart' as p; void main() { late FakeNetworkWatch network; late MobileDataGate gate; setUp(() { network = FakeNetworkWatch(); gate = MobileDataGate(network: network, offered: true); addTearDown(gate.dispose); }); test('on Wi-Fi everything goes, whatever is set', () async { await gate.ready; for (final setting in MobileData.values) { await gate.choose(setting); expect(gate.metered, isFalse); expect(gate.allowance, SyncAllowance.everything); expect(gate.filesAllowed, isTrue); } }); test('on mobile data, asking holds back everything until answered', () async { network.state = FakeNetworkWatch.mobile; await gate.ready; expect(gate.metered, isTrue); expect(gate.allowance, SyncAllowance.nothing); expect(gate.filesAllowed, isFalse); gate.answer(SyncAllowance.rows); expect(gate.allowance, SyncAllowance.rows, reason: 'without files'); expect(gate.filesAllowed, isFalse); gate.answer(SyncAllowance.everything); expect(gate.filesAllowed, isTrue); }); test("set to Without files or Everything, mobile data doesn't ask", () async { network.state = FakeNetworkWatch.mobile; await gate.ready; await gate.choose(MobileData.withoutFiles); expect(gate.allowance, SyncAllowance.rows); await gate.choose(MobileData.everything); expect(gate.allowance, SyncAllowance.everything); }); test('an answer holds until the connection changes: Wi-Fi come and gone, ' 'or another metered network, asks again', () async { network.state = FakeNetworkWatch.mobile; await gate.ready; var changes = 0; gate ..addListener(() => changes++) ..answer(SyncAllowance.everything); expect(changes, 1); network.moveTo(FakeNetworkWatch.mobile); expect(changes, 1, reason: 'the same network again changes nothing'); expect(gate.allowance, SyncAllowance.everything); network ..moveTo(FakeNetworkWatch.wifi) ..moveTo(FakeNetworkWatch.mobile); expect(gate.allowance, SyncAllowance.nothing); gate.answer(SyncAllowance.everything); network.moveTo((id: 'hotspot', metered: true)); expect(gate.allowance, SyncAllowance.nothing); }); test('nothing is answered off a metered network', () async { await gate.ready; gate.answer(SyncAllowance.everything); network.moveTo(FakeNetworkWatch.mobile); expect(gate.allowance, SyncAllowance.nothing); }); test('a desktop is never metered, and is offered no choice', () async { final desktop = MobileDataGate(); addTearDown(desktop.dispose); await desktop.ready; expect(desktop.offered, isFalse); expect(desktop.allowance, SyncAllowance.everything); }); group('kept on the device', () { late Directory folder; setUp(() async { folder = await Directory.systemTemp.createTemp('mobile_data'); addTearDown(() => folder.delete(recursive: true)); }); test('the setting stays when the app opens again; an answer goes with ' 'the app', () async { final file = File(p.join(folder.path, 'mobile_data.json')); network.state = FakeNetworkWatch.mobile; final first = await MobileDataGate.open( file, network: network, offered: true, ); addTearDown(first.dispose); await first.ready; await first.choose(MobileData.withoutFiles); final again = await MobileDataGate.open( file, network: network, offered: true, ); addTearDown(again.dispose); await again.ready; expect(again.mobileData, MobileData.withoutFiles); await again.choose(MobileData.ask); again.answer(SyncAllowance.everything); final third = await MobileDataGate.open( file, network: network, offered: true, ); addTearDown(third.dispose); await third.ready; expect(third.allowance, SyncAllowance.nothing); }); test('a file that is no setting asks', () async { final file = File(p.join(folder.path, 'mobile_data.json')); for (final content in ['not json', '[1]', '{"mobileData": "never"}']) { await file.writeAsString(content); final gate = await MobileDataGate.open( file, network: network, offered: true, ); addTearDown(gate.dispose); expect(gate.mobileData, MobileData.ask, reason: content); } }); }); }