blob: d3bedf1470a09af43261af9edebe447f6a22daad [file]
// Copyright 2021 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
import 'dart:async';
import 'package:devtools_app/devtools_app.dart';
import 'package:devtools_app/src/shared/console/eval/auto_complete.dart';
import 'package:devtools_app_shared/service.dart';
import 'package:devtools_app_shared/utils.dart';
import 'package:devtools_test/helpers.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../test_infra/flutter_test_driver.dart';
import '../../test_infra/flutter_test_environment.dart';
import '../../test_infra/flutter_test_storage.dart';
void main() {
setGlobal(Storage, FlutterTestStorage());
final env = FlutterTestEnvironment(
const FlutterRunConfiguration(withDebugger: true),
);
late Disposable isAlive;
late DebuggerController debuggerController;
late EvalOnDartLibrary eval;
setUp(() async {
setGlobal(
DevToolsEnvironmentParameters,
ExternalDevToolsEnvironmentParameters(),
);
setGlobal(BreakpointManager, BreakpointManager());
setGlobal(EvalService, EvalService());
setGlobal(NotificationService, NotificationService());
isAlive = Disposable();
await env.setupEnvironment();
debuggerController = DebuggerController();
eval = EvalOnDartLibrary(
'package:flutter_app/src/autocomplete.dart',
serviceConnection.serviceManager.service!,
serviceManager: serviceConnection.serviceManager,
disableBreakpoints: false,
);
});
tearDown(() async {
await debuggerController.resume();
isAlive.dispose();
debuggerController.dispose();
await env.tearDownEnvironment();
});
tearDownAll(() async {
await env.tearDownEnvironment(force: true);
});
Future<void> runMethodAndWaitForPause(String method) async {
unawaited(eval.eval(method, isAlive: isAlive));
await whenMatches(debuggerController.selectedStackFrame, (f) => f != null);
}
group('EvalOnDartLibrary', () {
test(
'returns scoped variables when EditingParts is not a field',
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
expect(
await autoCompleteResultsFor(
EditingParts(activeWord: 'foo', leftSide: '', rightSide: ''),
evalService,
),
equals(['foo', 'foobar']),
);
expect(
await autoCompleteResultsFor(
EditingParts(activeWord: 'b', leftSide: '', rightSide: ''),
evalService,
),
equals(['bar', 'baz']),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
test(
'returns filtered members when EditingParts is a field ',
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
expect(
await autoCompleteResultsFor(
EditingParts(activeWord: 'f', leftSide: 'foo.', rightSide: ''),
evalService,
),
equals(['field1', 'field2', 'func1', 'func2']),
);
expect(
await autoCompleteResultsFor(
EditingParts(activeWord: 'fu', leftSide: 'foo.', rightSide: ''),
evalService,
),
equals(['func1', 'func2']),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
test(
'returns filtered members when EditingParts is a class name ',
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
expect(
await autoCompleteResultsFor(
EditingParts(leftSide: 'FooClass.', activeWord: '', rightSide: ''),
evalService,
),
equals([
'staticField1',
'staticField2',
'namedConstructor',
'factory1',
'staticMethod',
]),
);
expect(
await autoCompleteResultsFor(
EditingParts(
activeWord: 'fa',
leftSide: 'FooClass.',
rightSide: '',
),
evalService,
),
equals(['factory1']),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
test(
'returns privates only from library',
// TODO(https://github.com/flutter/devtools/issues/7099): unskip once
// this test flake is fixed.
skip: true,
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
await expectLater(
autoCompleteResultsFor(
EditingParts(activeWord: '_', leftSide: '', rightSide: ''),
evalService,
),
completion(
unorderedEquals([
'_privateField2',
'_privateField1',
'_PrivateClass',
]),
),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
test(
'returns exported members from import',
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
expect(
await autoCompleteResultsFor(
EditingParts(
activeWord: 'exportedField',
leftSide: '',
rightSide: '',
),
evalService,
),
equals(['exportedField']),
);
expect(
await autoCompleteResultsFor(
EditingParts(
activeWord: 'ExportedClass',
leftSide: '',
rightSide: '',
),
evalService,
),
equals(['ExportedClass']),
);
// Privates are not exported
expect(
await autoCompleteResultsFor(
EditingParts(
activeWord: '_privateExportedField',
leftSide: '',
rightSide: '',
),
evalService,
),
equals([]),
);
expect(
await autoCompleteResultsFor(
EditingParts(
activeWord: '_PrivateExportedClass',
leftSide: '',
rightSide: '',
),
evalService,
),
equals([]),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
test(
'returns prefixes of libraries imported',
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
expect(
await autoCompleteResultsFor(
EditingParts(activeWord: 'developer', leftSide: '', rightSide: ''),
evalService,
),
equals(['developer']),
);
expect(
await autoCompleteResultsFor(
EditingParts(activeWord: 'math', leftSide: '', rightSide: ''),
evalService,
),
equals(['math']),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
test(
'returns no operators for int',
// Temporarily skip this test while Flutter gets a Dart SDK with new
// properties on 'int'.
skip: true,
() async {
await runMethodAndWaitForPause(
'AnotherClass().pauseWithScopedVariablesMethod()',
);
expect(
await autoCompleteResultsFor(
EditingParts(leftSide: '7.', activeWord: '', rightSide: ''),
evalService,
),
equals([
'hashCode',
'bitLength',
'toString',
'remainder',
'abs',
'sign',
'isEven',
'isOdd',
'isNaN',
'isNegative',
'isInfinite',
'isFinite',
'toUnsigned',
'toSigned',
'compareTo',
'round',
'floor',
'ceil',
'truncate',
'roundToDouble',
'floorToDouble',
'ceilToDouble',
'truncateToDouble',
'clamp',
'toInt',
'toDouble',
'toStringAsFixed',
'toStringAsExponential',
'toStringAsPrecision',
'toRadixString',
'modPow',
'modInverse',
'gcd',
'noSuchMethod',
'runtimeType',
]),
);
},
timeout: const Timeout.factor(8),
tags: includeForCustomerTestsTag,
);
});
}