Add flutter analysis tests (#585)
diff --git a/test/all.dart b/test/all.dart
index 4fb2e80..a50d34b 100644
--- a/test/all.dart
+++ b/test/all.dart
@@ -11,6 +11,7 @@
import 'common_server_api_test.dart' as common_server_api_test;
import 'common_test.dart' as common_test;
import 'compiler_test.dart' as compiler_test;
+import 'flutter_analysis_server_test.dart' as flutter_analysis_server_test;
import 'flutter_web_test.dart' as flutter_web_test;
import 'gae_deployed_test.dart' as gae_deployed_test;
import 'pub_test.dart' as pub_test;
@@ -25,6 +26,7 @@
common_server_api_protobuf_test.defineTests();
common_test.defineTests();
compiler_test.defineTests();
+ flutter_analysis_server_test.defineTests();
flutter_web_test.defineTests();
gae_deployed_test.defineTests();
pub_test.defineTests();
diff --git a/test/flutter_analysis_server_test.dart b/test/flutter_analysis_server_test.dart
new file mode 100644
index 0000000..17b5d04
--- /dev/null
+++ b/test/flutter_analysis_server_test.dart
@@ -0,0 +1,230 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.flutter_analyzer_server_test;
+
+import 'package:dart_services/src/analysis_server.dart';
+import 'package:dart_services/src/protos/dart_services.pb.dart' as proto;
+import 'package:dart_services/src/flutter_web.dart';
+import 'package:dart_services/src/sdk_manager.dart';
+import 'package:test/test.dart';
+
+const counter = r'''
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. 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:flutter/material.dart';
+
+void main() => runApp(MyApp());
+
+class MyApp extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Demo',
+ debugShowCheckedModeBanner: false,
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ ),
+ home: MyHomePage(title: 'Flutter Demo Home Page'),
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ MyHomePage({Key key, this.title}) : super(key: key);
+
+ final String title;
+
+ @override
+ _MyHomePageState createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State<MyHomePage> {
+ int _counter = 0;
+
+ void _incrementCounter() {
+ setState(() {
+ _counter++;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text(widget.title),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: <Widget>[
+ Text(
+ 'You have pushed the button this many times:',
+ ),
+ Text(
+ '$_counter',
+ style: Theme.of(context).textTheme.headline4,
+ ),
+ ],
+ ),
+ ),
+ floatingActionButton: FloatingActionButton(
+ onPressed: _incrementCounter,
+ tooltip: 'Increment',
+ child: Icon(Icons.add),
+ ),
+ );
+ }
+}
+''';
+
+const draggableAndPhysics = '''
+import 'package:flutter/material.dart';
+import 'package:flutter/physics.dart';
+
+main() {
+ runApp(
+ MaterialApp(
+ debugShowCheckedModeBanner: false,
+ home: PhysicsCardDragDemo(),
+ ),
+ );
+}
+
+class PhysicsCardDragDemo extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text('A draggable card!'),
+ ),
+ body: DraggableCard(
+ child: FlutterLogo(
+ size: 128,
+ ),
+ ),
+ );
+ }
+}
+
+class DraggableCard extends StatefulWidget {
+ final Widget child;
+ DraggableCard({this.child});
+
+ @override
+ _DraggableCardState createState() => _DraggableCardState();
+}
+
+class _DraggableCardState extends State<DraggableCard>
+ with SingleTickerProviderStateMixin {
+ AnimationController _controller;
+ Alignment _dragAlignment = Alignment.center;
+ Animation<Alignment> _animation;
+
+ void _runAnimation(Offset pixelsPerSecond, Size size) {
+ _animation = _controller.drive(
+ AlignmentTween(
+ begin: _dragAlignment,
+ end: Alignment.center,
+ ),
+ );
+
+ final unitsPerSecondX = pixelsPerSecond.dx / size.width;
+ final unitsPerSecondY = pixelsPerSecond.dy / size.height;
+ final unitsPerSecond = Offset(unitsPerSecondX, unitsPerSecondY);
+ final unitVelocity = unitsPerSecond.distance;
+
+ const spring = SpringDescription(
+ mass: 30,
+ stiffness: 1,
+ damping: 1,
+ );
+
+ final simulation = SpringSimulation(spring, 0, 1, -unitVelocity);
+
+ _controller.animateWith(simulation);
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _controller = AnimationController(vsync: this);
+
+ _controller.addListener(() {
+ setState(() {
+ _dragAlignment = _animation.value;
+ });
+ });
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final size = MediaQuery.of(context).size;
+ return GestureDetector(
+ onPanDown: (details) {
+ _controller.stop();
+ },
+ onPanUpdate: (details) {
+ setState(() {
+ _dragAlignment += Alignment(
+ details.delta.dx / (size.width / 2),
+ details.delta.dy / (size.height / 2),
+ );
+ });
+ },
+ onPanEnd: (details) {
+ _runAnimation(details.velocity.pixelsPerSecond, size);
+ },
+ child: Align(
+ alignment: _dragAlignment,
+ child: Card(
+ child: widget.child,
+ ),
+ ),
+ );
+ }
+}
+''';
+
+void main() => defineTests();
+
+void defineTests() {
+ AnalysisServerWrapper analysisServer;
+ FlutterWebManager flutterWebManager;
+
+ group('Flutter SDK analysis_server', () {
+ setUp(() async {
+ flutterWebManager = FlutterWebManager(SdkManager.flutterSdk);
+ await flutterWebManager.initFlutterWeb();
+ analysisServer = AnalysisServerWrapper(
+ SdkManager.flutterSdk.sdkPath, flutterWebManager);
+ await analysisServer.init();
+ await analysisServer.warmup();
+ });
+
+ tearDown(() => analysisServer.shutdown());
+
+ test('analyze counter app', () async {
+ final results = await analysisServer.analyze(counter);
+ expect(results.issues, isEmpty);
+ });
+
+ test('analyze Draggable Physics sample', () async {
+ final results = await analysisServer.analyze(draggableAndPhysics);
+ expect(results.issues, isEmpty);
+ });
+ });
+}
+
+bool completionsContains(proto.CompleteResponse response, String expected) =>
+ response.completions
+ .any((completion) => completion.completion['completion'] == expected);