// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:collection/collection.dart' show ListEquality, MapEquality; import 'package:flutter_devicelab/framework/devices.dart'; import 'package:meta/meta.dart'; import 'common.dart'; void main() { group('device', () { late Device device; setUp(() { FakeDevice.resetLog(); device = FakeDevice(deviceId: 'fakeDeviceId'); }); tearDown(() { }); group('cpu check', () { test('arm64', () async { FakeDevice.pretendArm64(); final AndroidDevice androidDevice = device as AndroidDevice; expect(await androidDevice.isArm64(), isTrue); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'getprop', arguments: ['ro.product.cpu.abi']), ]); }); }); group('isAwake/isAsleep', () { test('reads Awake', () async { FakeDevice.pretendAwake(); expect(await device.isAwake(), isTrue); expect(await device.isAsleep(), isFalse); }); test('reads Awake - samsung devices', () async { FakeDevice.pretendAwakeSamsung(); expect(await device.isAwake(), isTrue); expect(await device.isAsleep(), isFalse); }); test('reads Asleep', () async { FakeDevice.pretendAsleep(); expect(await device.isAwake(), isFalse); expect(await device.isAsleep(), isTrue); }); }); group('togglePower', () { test('sends power event', () async { await device.togglePower(); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'input', arguments: ['keyevent', '26']), ]); }); }); group('wakeUp', () { test('when awake', () async { FakeDevice.pretendAwake(); await device.wakeUp(); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'dumpsys', arguments: ['power']), ]); }); test('when asleep', () async { FakeDevice.pretendAsleep(); await device.wakeUp(); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'dumpsys', arguments: ['power']), cmd(command: 'input', arguments: ['keyevent', '26']), ]); }); }); group('sendToSleep', () { test('when asleep', () async { FakeDevice.pretendAsleep(); await device.sendToSleep(); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'dumpsys', arguments: ['power']), ]); }); test('when awake', () async { FakeDevice.pretendAwake(); await device.sendToSleep(); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'dumpsys', arguments: ['power']), cmd(command: 'input', arguments: ['keyevent', '26']), ]); }); }); group('unlock', () { test('sends unlock event', () async { FakeDevice.pretendAwake(); await device.unlock(); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'dumpsys', arguments: ['power']), cmd(command: 'input', arguments: ['keyevent', '82']), ]); }); }); group('adb', () { test('tap', () async { await device.tap(100, 200); expectLog([ cmd(command: 'getprop', arguments: ['ro.bootimage.build.fingerprint', ';', 'getprop', 'ro.build.version.release', ';', 'getprop', 'ro.build.version.sdk']), cmd(command: 'input', arguments: ['tap', '100', '200']), ]); }); }); }); } void expectLog(List log) { expect(FakeDevice.commandLog, log); } CommandArgs cmd({ required String command, List? arguments, Map? environment, }) { return CommandArgs( command: command, arguments: arguments, environment: environment, ); } @immutable class CommandArgs { const CommandArgs({ required this.command, this.arguments, this.environment }); final String command; final List? arguments; final Map? environment; @override String toString() => 'CommandArgs(command: $command, arguments: $arguments, environment: $environment)'; @override bool operator==(Object other) { if (other.runtimeType != CommandArgs) { return false; } return other is CommandArgs && other.command == command && const ListEquality().equals(other.arguments, arguments) && const MapEquality().equals(other.environment, environment); } @override int get hashCode { return Object.hash( command, Object.hashAll(arguments ?? const []), Object.hashAllUnordered(environment?.keys ?? const []), Object.hashAllUnordered(environment?.values ?? const []), ); } } class FakeDevice extends AndroidDevice { FakeDevice({required super.deviceId}); static String output = ''; static List commandLog = []; static void resetLog() { commandLog.clear(); } static void pretendAwake() { output = ''' mWakefulness=Awake '''; } static void pretendAwakeSamsung() { output = ''' getWakefulnessLocked()=Awake '''; } static void pretendAsleep() { output = ''' mWakefulness=Asleep '''; } static void pretendArm64() { output = ''' arm64 '''; } @override Future shellEval(String command, List arguments, { Map? environment, bool silent = false }) async { commandLog.add(CommandArgs( command: command, arguments: arguments, environment: environment, )); return output; } @override Future shellExec(String command, List arguments, { Map? environment, bool silent = false }) async { commandLog.add(CommandArgs( command: command, arguments: arguments, environment: environment, )); } }