import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:appsok/src/services/adb_service.dart'; void main() { group('AdbRuntimeConfig', () { test('prefers bundled adb when it exists', () { final tempDir = Directory.systemTemp.createTempSync( 'appsok-adb-runtime-', ); addTearDown(() => tempDir.deleteSync(recursive: true)); final bundledAdb = File('${tempDir.path}/adb')..writeAsStringSync(''); final runtime = AdbRuntimeConfig( bundledAdbPath: bundledAdb.path, ).resolve(); expect(runtime.executablePath, bundledAdb.path); expect(runtime.source, AdbExecutableSource.bundled); expect(runtime.bundledExists, isTrue); expect(runtime.fallbackUsed, isFalse); expect(runtime.serverPort, AdbRuntimeConfig.defaultAppSokServerPort); }); test('falls back to system adb when bundled adb is missing', () { final runtime = const AdbRuntimeConfig( bundledAdbPath: '/tmp/appsok-missing-adb', ).resolve(); expect(runtime.executablePath, AdbRuntimeConfig.systemAdbPath); expect(runtime.source, AdbExecutableSource.system); expect(runtime.bundledExists, isFalse); expect(runtime.fallbackUsed, isTrue); }); test('uses custom adb as an explicit override', () { final tempDir = Directory.systemTemp.createTempSync( 'appsok-adb-runtime-', ); addTearDown(() => tempDir.deleteSync(recursive: true)); final bundledAdb = File('${tempDir.path}/adb')..writeAsStringSync(''); final runtime = AdbRuntimeConfig( bundledAdbPath: bundledAdb.path, customAdbPath: '/custom/platform-tools/adb', ).resolve(); expect(runtime.executablePath, '/custom/platform-tools/adb'); expect(runtime.source, AdbExecutableSource.custom); expect(runtime.fallbackUsed, isFalse); }); test('uses shared ADB server port when requested', () { final runtime = const AdbRuntimeConfig( serverMode: AdbServerMode.shared, ).resolve(); expect(runtime.serverPort, AdbRuntimeConfig.sharedServerPort); expect(runtime.environment, {'ADB_SERVER_PORT': '5037'}); }); }); group('AdbService', () { test( 'runs adb devices with the resolved executable and server port', () async { final calls = <({String executable, List args, String? port})>[]; final service = AdbService( runtimeConfig: const AdbRuntimeConfig( customAdbPath: '/opt/appsok/adb', serverPort: 15037, ), processRunner: (executable, args, {environment}) async { calls.add(( executable: executable, args: args, port: environment?['ADB_SERVER_PORT'], )); return ProcessResult( 42, 0, 'List of devices attached\n' 'emulator-5554 device product:emu64a ' 'model:sdk_gphone64_arm64 device:emu64a\n', '', ); }, ); final devices = await service.listDevices(); expect(calls, hasLength(1)); expect(calls.single.executable, '/opt/appsok/adb'); expect(calls.single.args, ['devices', '-l']); expect(calls.single.port, '15037'); expect(devices.single.serial, 'emulator-5554'); expect(devices.single.state, 'device'); expect(devices.single.model, 'sdk_gphone64_arm64'); }, ); test('runs adb install with the shared server port', () async { final calls = <({List args, String? port})>[]; final service = AdbService( runtimeConfig: const AdbRuntimeConfig( customAdbPath: '/opt/appsok/adb', serverMode: AdbServerMode.shared, ), processRunner: (_, args, {environment}) async { calls.add((args: args, port: environment?['ADB_SERVER_PORT'])); return ProcessResult(42, 0, 'Success', ''); }, ); final result = await service.installApk( serial: 'R5CT90A1B2C', apkPath: '/tmp/app.apk', ); expect(result.succeeded, isTrue); expect(calls.single.args, [ '-s', 'R5CT90A1B2C', 'install', '-r', '/tmp/app.apk', ]); expect(calls.single.port, '5037'); }); }); }