Add partial code tests for extension methods

Change-Id: I5886c275383302566e997cb2f7e968c446b79369
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105160
Reviewed-by: Dan Rubel <danrubel@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/extension_declaration_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/extension_declaration_test.dart
new file mode 100644
index 0000000..e04eadd
--- /dev/null
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/extension_declaration_test.dart
@@ -0,0 +1,87 @@
+// 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:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+
+import 'partial_code_support.dart';
+
+main() {
+  new ExtensionDeclarationTest().buildAll();
+}
+
+class ExtensionDeclarationTest extends PartialCodeTest {
+  buildAll() {
+    buildTests(
+        'extension_declaration',
+        [
+          new TestDescriptor(
+              'keyword',
+              'extension',
+              [
+                ParserErrorCode.MISSING_IDENTIFIER,
+                ParserErrorCode.EXPECTED_TOKEN,
+                ParserErrorCode.EXPECTED_TYPE_NAME,
+                ParserErrorCode.EXPECTED_BODY,
+              ],
+              'extension _s_ on _s_ {}',
+              failing: ['getter', 'functionNonVoid', 'functionVoid', 'mixin']),
+          new TestDescriptor(
+              'named',
+              'extension E',
+              [
+                ParserErrorCode.EXPECTED_TOKEN,
+                ParserErrorCode.EXPECTED_TYPE_NAME,
+                ParserErrorCode.EXPECTED_BODY,
+              ],
+              'extension E on _s_ {}',
+              failing: ['getter', 'functionNonVoid', 'functionVoid', 'mixin']),
+          new TestDescriptor(
+              'on',
+              'extension E on',
+              [
+                ParserErrorCode.EXPECTED_TYPE_NAME,
+                ParserErrorCode.EXPECTED_BODY,
+              ],
+              'extension E on _s_ {}',
+              failing: ['getter', 'functionNonVoid', 'functionVoid', 'mixin']),
+          new TestDescriptor(
+              'extendedType',
+              'extension E on String',
+              [
+                ParserErrorCode.EXPECTED_BODY,
+              ],
+              'extension E on String {}'),
+          // Most of the failing tests are because the following text could be
+          // a member of the class, so the parser adds the closing brace _after_
+          // the declaration that's expected to follow it.
+          //
+          // The notable exceptions are 'class', 'enum', 'mixin', and 'typedef'.
+          new TestDescriptor(
+              'partialBody',
+              'extension E on String {',
+              [
+                ScannerErrorCode.EXPECTED_TOKEN,
+              ],
+              'extension E on String {}',
+              failing: [
+                'class',
+                'const',
+                'enum',
+                'final',
+                'functionNonVoid',
+                'functionVoid',
+                'mixin',
+                'getter',
+                'setter',
+                'typedef',
+                'var'
+              ]),
+        ],
+        PartialCodeTest.declarationSuffixes,
+        featureSet: new FeatureSet.forTesting(
+            sdkVersion: '2.3.0',
+            additionalFeatures: [Feature.extension_methods]));
+  }
+}
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/partial_code_support.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/partial_code_support.dart
index 8634b8f..45263e5 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/partial_code_support.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/partial_code_support.dart
@@ -2,6 +2,7 @@
 // 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:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
@@ -47,6 +48,7 @@
   static final List<TestSuffix> declarationSuffixes = <TestSuffix>[
     new TestSuffix('class', 'class A {}'),
     new TestSuffix('enum', 'enum E { v }'),
+//    new TestSuffix('extension', 'extension E on A {}'),
     new TestSuffix('mixin', 'mixin M {}'),
     new TestSuffix('typedef', 'typedef A = B Function(C, D);'),
     new TestSuffix('functionVoid', 'void f() {}'),
@@ -107,16 +109,21 @@
    */
   buildTests(String groupName, List<TestDescriptor> descriptors,
       List<TestSuffix> suffixes,
-      {String head, bool includeEof: true, String tail}) {
+      {FeatureSet featureSet,
+      String head,
+      bool includeEof: true,
+      String tail}) {
     group(groupName, () {
       for (TestDescriptor descriptor in descriptors) {
         if (includeEof) {
           _buildTestForDescriptorAndSuffix(
-              descriptor, TestSuffix.eof, 0, head, tail);
+              descriptor, TestSuffix.eof, 0, head, tail,
+              featureSet: featureSet);
         }
         for (int i = 0; i < suffixes.length; i++) {
           _buildTestForDescriptorAndSuffix(
-              descriptor, suffixes[i], i + 1, head, tail);
+              descriptor, suffixes[i], i + 1, head, tail,
+              featureSet: featureSet);
         }
         if (descriptor.failing != null) {
           test('${descriptor.name}_failingList', () {
@@ -138,7 +145,8 @@
    * Build a single test based on the given [descriptor] and [suffix].
    */
   _buildTestForDescriptorAndSuffix(TestDescriptor descriptor, TestSuffix suffix,
-      int suffixIndex, String head, String tail) {
+      int suffixIndex, String head, String tail,
+      {FeatureSet featureSet}) {
     test('${descriptor.name}_${suffix.name}', () {
       //
       // Compose the invalid and valid pieces of code.
@@ -172,7 +180,7 @@
       //
       GatheringErrorListener listener =
           new GatheringErrorListener(checkRanges: true);
-      parseCompilationUnit2(base.toString(), listener);
+      parseCompilationUnit2(base.toString(), listener, featureSet: featureSet);
       var baseErrorCodes = <ErrorCode>[];
       listener.errors.forEach((AnalysisError error) {
         if (error.errorCode == ParserErrorCode.BREAK_OUTSIDE_OF_LOOP ||
@@ -218,7 +226,8 @@
             invalid.toString(), expectedInvalidCodeErrors, valid.toString(),
             adjustValidUnitBeforeComparison:
                 descriptor.adjustValidUnitBeforeComparison,
-            expectedErrorsInValidCode: expectedValidCodeErrors);
+            expectedErrorsInValidCode: expectedValidCodeErrors,
+            featureSet: featureSet);
       }
     });
   }
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/test_all.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/test_all.dart
index 768c05b..0b20072 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/test_all.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/test_all.dart
@@ -13,6 +13,7 @@
 import 'do_statement_test.dart' as do_statement;
 import 'enum_declaration_test.dart' as enum_declaration;
 import 'export_directive_test.dart' as export_directive;
+import 'extension_declaration_test.dart' as extension_declaration;
 import 'field_declaration_test.dart' as field_declaration;
 import 'forEach_statement_test.dart' as forEach_statement;
 import 'for_statement_test.dart' as for_statement;
@@ -46,6 +47,7 @@
     do_statement.main();
     enum_declaration.main();
     export_directive.main();
+    extension_declaration.main();
     field_declaration.main();
     for_statement.main();
     forEach_statement.main();