import 'dart:async'; import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences_platform_interface/in_memory_shared_preferences_async.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_async_platform_interface.dart'; import 'package:fruitshorts/core/config/app_config.dart'; import 'package:fruitshorts/core/config/server_endpoint.dart'; void main() { setUp(() { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.empty(); AppConfig.clearRuntimeBaseUrl(); AppConfig.ready = Future.value(); }); tearDown(() { AppConfig.clearRuntimeBaseUrl(); AppConfig.ready = Future.value(); }); test('should_normalize_http_urls_and_reject_invalid_values', () { expect( ServerEndpoint.normalize(' https://192.168.1.9:8081/// '), 'https://192.168.1.9:8081', ); expect( ServerEndpoint.normalize('http://example.test:8081/path/'), 'http://example.test:8081/path', ); expect(ServerEndpoint.normalize('ftp://example.test'), isNull); expect(ServerEndpoint.normalize('example.test:8081'), isNull); expect(ServerEndpoint.normalize('http://'), isNull); }); test('should_prioritize_runtime_over_dart_define_over_default', () { expect( ServerEndpoint.resolve( stored: ' http://runtime.test:8081/ ', compiled: 'http://define.test:8081', fallback: 'http://default.test:8081', ), 'http://runtime.test:8081', ); expect( ServerEndpoint.resolve( stored: 'ftp://invalid', compiled: 'http://define.test:8081/', fallback: 'http://default.test:8081', ), 'http://define.test:8081', ); expect( ServerEndpoint.resolve( stored: null, compiled: '', fallback: 'http://default.test:8081/', ), 'http://default.test:8081', ); }); test('should_use_the_configured_local_address_for_device_default', () { final uri = Uri.parse(AppConfig.devHostBaseUrl); expect(uri.scheme, 'http'); expect(uri.host, isNotEmpty); expect(uri.port, 8081); expect(uri.path, isEmpty); }); test('should_skip_probe_when_compiled_override_is_set', () async { const compiled = 'http://compiled.test:8081'; var probeCalls = 0; await AppConfig.probeAndApplyBaseUrl( compiledOverride: compiled, probe: (_) async { probeCalls++; return true; }, ); expect(probeCalls, 0); expect(AppConfig.apiBaseUrl, compiled); }); test('should_keep_runtime_endpoint_when_compiled_override_is_set', () async { const runtime = 'http://runtime.test:8081'; const compiled = 'http://compiled.test:8081'; var probeCalls = 0; AppConfig.applyRuntimeBaseUrl(runtime); await AppConfig.probeAndApplyBaseUrl( compiledOverride: compiled, probe: (_) async { probeCalls++; return true; }, ); expect(probeCalls, 0); expect(AppConfig.apiBaseUrl, runtime); }); test('should_keep_probing_when_compiled_override_is_empty', () async { final attempts = []; await AppConfig.probeAndApplyBaseUrl( compiledOverride: '', probe: (baseUrl) async { attempts.add(baseUrl); return baseUrl == AppConfig.publicBaseUrl; }, ); expect(attempts, [ AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl, AppConfig.publicBaseUrl, ]); expect(AppConfig.apiBaseUrl, AppConfig.publicBaseUrl); }); test( 'should_probe_all_candidates_in_parallel_before_applying_priority', () async { final attempts = []; var active = 0; var maxActive = 0; final allStarted = Completer(); final probing = AppConfig.probeAndApplyBaseUrl( fallbackBaseUrl: AppConfig.devHostBaseUrl, probe: (baseUrl) async { attempts.add(baseUrl); active++; if (active > maxActive) maxActive = active; if (active == 3) allStarted.complete(); await allStarted.future; active--; return baseUrl == AppConfig.lanBaseUrl || baseUrl == AppConfig.devHostBaseUrl; }, ); await probing.timeout(const Duration(seconds: 1)); expect(attempts, [ AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl, AppConfig.publicBaseUrl, ]); expect(maxActive, 3); expect(AppConfig.apiBaseUrl, AppConfig.lanBaseUrl); }, ); test('should_probe_loopback_then_public_in_order', () async { final attempts = []; await AppConfig.probeAndApplyBaseUrl( fallbackBaseUrl: AppConfig.devHostBaseUrl, probe: (baseUrl) async { attempts.add(baseUrl); return baseUrl == AppConfig.publicBaseUrl; }, ); expect(attempts, [ AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl, AppConfig.publicBaseUrl, ]); expect(AppConfig.apiBaseUrl, AppConfig.publicBaseUrl); }); test('should_use_platform_default_when_all_probes_fail', () async { final attempts = []; await AppConfig.probeAndApplyBaseUrl( fallbackBaseUrl: AppConfig.devHostBaseUrl, probe: (baseUrl) async { attempts.add(baseUrl); return false; }, ); expect(attempts, [ AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl, AppConfig.publicBaseUrl, ]); expect(AppConfig.apiBaseUrl, AppConfig.devHostBaseUrl); }); test('should_probe_explicit_runtime_endpoint_first', () async { const custom = 'http://custom.test:8081'; final attempts = []; AppConfig.applyRuntimeBaseUrl(custom); await AppConfig.probeAndApplyBaseUrl( probe: (baseUrl) async { attempts.add(baseUrl); return baseUrl == custom; }, ); expect(attempts, [ custom, AppConfig.lanBaseUrl, AppConfig.devHostBaseUrl, AppConfig.publicBaseUrl, ]); expect(AppConfig.apiBaseUrl, custom); }); test('should_apply_stored_url_only_when_debug_is_enabled', () async { SharedPreferencesAsyncPlatform.instance = InMemorySharedPreferencesAsync.withData({ ServerEndpoint.preferenceKey: ' http://192.168.31.187:8081/ ', }); final original = AppConfig.apiBaseUrl; await ServerEndpoint.load(debug: false); expect(AppConfig.apiBaseUrl, original); await ServerEndpoint.load(debug: true); expect(AppConfig.apiBaseUrl, 'http://192.168.31.187:8081'); }); test('should_save_normalized_url_and_clear_override', () async { expect(await ServerEndpoint.save('ftp://invalid'), isFalse); expect( await SharedPreferencesAsync().getString(ServerEndpoint.preferenceKey), isNull, ); expect(await ServerEndpoint.save(' http://192.168.31.187:8081/ '), isTrue); expect( await SharedPreferencesAsync().getString(ServerEndpoint.preferenceKey), 'http://192.168.31.187:8081', ); expect(AppConfig.apiBaseUrl, 'http://192.168.31.187:8081'); await ServerEndpoint.clear(); expect( await SharedPreferencesAsync().getString(ServerEndpoint.preferenceKey), isNull, ); }); }