| // 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 'dart:async'; |
| import 'dart:io'; |
| |
| import 'package:file/file.dart'; |
| import 'package:flutter_tools/src/base/file_system.dart'; |
| import 'package:matcher/matcher.dart'; |
| |
| import 'package:vm_service/vm_service.dart'; |
| |
| import '../src/common.dart'; |
| import 'test_data/basic_project.dart'; |
| import 'test_data/tests_project.dart'; |
| import 'test_driver.dart'; |
| import 'test_utils.dart'; |
| |
| void batch1() { |
| final BasicProject _project = BasicProject(); |
| Directory tempDir; |
| FlutterRunTestDriver _flutter; |
| |
| Future<void> initProject() async { |
| tempDir = createResolvedTempDirectorySync('run_expression_eval_test.'); |
| await _project.setUpIn(tempDir); |
| _flutter = FlutterRunTestDriver(tempDir); |
| } |
| |
| Future<void> cleanProject() async { |
| await _flutter.stop(); |
| tryToDelete(tempDir); |
| } |
| |
| Future<void> start({bool expressionEvaluation}) { |
| // The non-test project has a loop around its breakpoints. |
| // No need to start paused as all breakpoint would be eventually reached. |
| return _flutter.run( |
| withDebugger: true, chrome: true, |
| expressionEvaluation: expressionEvaluation); |
| } |
| |
| Future<void> breakInBuildMethod(FlutterTestDriver flutter) async { |
| await _flutter.breakAt( |
| _project.buildMethodBreakpointUri, |
| _project.buildMethodBreakpointLine, |
| ); |
| } |
| |
| Future<void> breakInTopLevelFunction(FlutterTestDriver flutter) async { |
| await _flutter.breakAt( |
| _project.topLevelFunctionBreakpointUri, |
| _project.topLevelFunctionBreakpointLine, |
| ); |
| } |
| |
| test('flutter run expression evaluation - error if expression evaluation disabled', () async { |
| await initProject(); |
| await start(expressionEvaluation: false); |
| await breakInTopLevelFunction(_flutter); |
| await failToEvaluateExpression(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter run expression evaluation - no native javascript objects in static scope', () async { |
| await initProject(); |
| await start(expressionEvaluation: true); |
| await breakInTopLevelFunction(_flutter); |
| await checkStaticScope(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter run expression evaluation - can handle compilation errors', () async { |
| await initProject(); |
| await start(expressionEvaluation: true); |
| await breakInTopLevelFunction(_flutter); |
| await evaluateErrorExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter run expression evaluation - can evaluate trivial expressions in top level function', () async { |
| await initProject(); |
| await start(expressionEvaluation: true); |
| await breakInTopLevelFunction(_flutter); |
| await evaluateTrivialExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter run expression evaluation - can evaluate trivial expressions in build method', () async { |
| await initProject(); |
| await start(expressionEvaluation: true); |
| await breakInBuildMethod(_flutter); |
| await evaluateTrivialExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter run expression evaluation - can evaluate complex expressions in top level function', () async { |
| await initProject(); |
| await start(expressionEvaluation: true); |
| await breakInTopLevelFunction(_flutter); |
| await evaluateComplexExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter run expression evaluation - can evaluate complex expressions in build method', () async { |
| await initProject(); |
| await _flutter.run(withDebugger: true, chrome: true); |
| await breakInBuildMethod(_flutter); |
| await evaluateComplexExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| } |
| |
| void batch2() { |
| final TestsProject _project = TestsProject(); |
| Directory tempDir; |
| FlutterRunTestDriver _flutter; |
| |
| Future<void> initProject() async { |
| tempDir = createResolvedTempDirectorySync('test_expression_eval_test.'); |
| await _project.setUpIn(tempDir); |
| _flutter = FlutterRunTestDriver(tempDir); |
| } |
| |
| Future<void> cleanProject() async { |
| await _flutter.stop(); |
| tryToDelete(tempDir); |
| } |
| |
| Future<void> breakInMethod(FlutterTestDriver flutter) async { |
| await _flutter.addBreakpoint( |
| _project.breakpointAppUri, |
| _project.breakpointLine, |
| ); |
| await _flutter.resume(); |
| await _flutter.waitForPause(); |
| } |
| |
| Future<void> startPaused({bool expressionEvaluation}) { |
| // The test project does not have a loop around its breakpoints. |
| // Start paused so we can set a breakpoint before passing it |
| // in the execution. |
| return _flutter.run( |
| withDebugger: true, chrome: true, |
| expressionEvaluation: expressionEvaluation, |
| startPaused: true, script: _project.testFilePath); |
| } |
| |
| test('flutter test expression evaluation - error if expression evaluation disabled', () async { |
| await initProject(); |
| await startPaused(expressionEvaluation: false); |
| await breakInMethod(_flutter); |
| await failToEvaluateExpression(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter test expression evaluation - can evaluate trivial expressions in a test', () async { |
| await initProject(); |
| await startPaused(expressionEvaluation: true); |
| await breakInMethod(_flutter); |
| await evaluateTrivialExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| |
| test('flutter test expression evaluation - can evaluate complex expressions in a test', () async { |
| await initProject(); |
| await startPaused(expressionEvaluation: true); |
| await breakInMethod(_flutter); |
| await evaluateComplexExpressions(_flutter); |
| await cleanProject(); |
| }, skip: 'CI not setup for web tests'); // https://github.com/flutter/flutter/issues/53779 |
| } |
| |
| Future<void> failToEvaluateExpression(FlutterTestDriver flutter) async { |
| ObjRef res; |
| try { |
| res = await flutter.evaluateInFrame('"test"'); |
| } on RPCError catch (e) { |
| expect(e.message, contains( |
| 'UnimplementedError: ' |
| 'Expression evaluation is not supported for this configuration')); |
| } |
| expect(res, null); |
| } |
| |
| Future<void> checkStaticScope(FlutterTestDriver flutter) async { |
| final Frame res = await flutter.getTopStackFrame(); |
| expect(res.vars, equals(<BoundVariable>[])); |
| } |
| |
| Future<void> evaluateErrorExpressions(FlutterTestDriver flutter) async { |
| final ObjRef res = await flutter.evaluateInFrame('typo'); |
| expectError(res, 'CompilationError: Getter not found: \'typo\'.\ntypo\n^^^^'); |
| } |
| |
| Future<void> evaluateTrivialExpressions(FlutterTestDriver flutter) async { |
| ObjRef res; |
| |
| res = await flutter.evaluateInFrame('"test"'); |
| expectInstance(res, InstanceKind.kString, 'test'); |
| |
| res = await flutter.evaluateInFrame('1'); |
| expectInstance(res, InstanceKind.kDouble, 1.toString()); |
| |
| res = await flutter.evaluateInFrame('true'); |
| expectInstance(res, InstanceKind.kBool, true.toString()); |
| } |
| |
| Future<void> evaluateComplexExpressions(FlutterTestDriver flutter) async { |
| final ObjRef res = await flutter.evaluateInFrame('new DateTime.now().year'); |
| expectInstance(res, InstanceKind.kDouble, DateTime.now().year.toString()); |
| } |
| |
| void expectInstance(ObjRef result, String kind, String message) { |
| expect(result, |
| const TypeMatcher<InstanceRef>() |
| .having((InstanceRef instance) => instance.kind, 'kind', kind) |
| .having((InstanceRef instance) => instance.valueAsString, 'valueAsString', message)); |
| } |
| |
| void expectError(ObjRef result, String message) { |
| expect(result, |
| const TypeMatcher<ErrorRef>() |
| .having((ErrorRef instance) => instance.message, 'message', message)); |
| } |
| |
| void main() { |
| batch1(); |
| batch2(); |
| } |