Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Unified Diff: pkg/analysis_server/test/completion_test_support.dart

Issue 785013002: Ported completion tests (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analysis_server/test/completion_test.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analysis_server/test/completion_test_support.dart
diff --git a/pkg/analysis_server/test/completion_test_support.dart b/pkg/analysis_server/test/completion_test_support.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ca41f3d316c1f93180cb4f94ce2ed03d9ec44353
--- /dev/null
+++ b/pkg/analysis_server/test/completion_test_support.dart
@@ -0,0 +1,236 @@
+// Copyright (c) 2014, 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 test.completion.support;
+
+import 'dart:collection';
+
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:unittest/unittest.dart';
+
+import 'domain_completion_test.dart';
+
+/**
+ * A base class for classes containing completion tests.
+ */
+class CompletionTestCase extends CompletionTest {
+ static const String CURSOR_MARKER = '!';
+
+ List get suggestedCompletions =>
+ suggestions.map(
+ (CompletionSuggestion suggestion) => suggestion.completion).toList();
+
+ void assertHasCompletion(String completion) {
+ int expectedOffset = completion.indexOf(CURSOR_MARKER);
+ if (expectedOffset >= 0) {
+ if (completion.indexOf(CURSOR_MARKER, expectedOffset + 1) >= 0) {
+ fail(
+ "Invalid completion, contains multiple cursor positions: '$completion'");
+ }
+ completion = completion.replaceFirst(CURSOR_MARKER, '');
+ } else {
+ expectedOffset = completion.length;
+ }
+ CompletionSuggestion matchingSuggestion;
+ suggestions.forEach((CompletionSuggestion suggestion) {
+ if (suggestion.completion == completion) {
+ if (matchingSuggestion == null) {
+ matchingSuggestion = suggestion;
+ } else {
+ fail(
+ "Expected exactly one '$completion' but found multiple:\n $suggestedCompletions");
+ }
+ }
+ });
+ if (matchingSuggestion == null) {
+ fail("Expected '$completion' but found none:\n $suggestedCompletions");
+ }
+ expect(matchingSuggestion.selectionOffset, equals(expectedOffset));
+ expect(matchingSuggestion.selectionLength, equals(0));
+ }
+
+ void assertHasNoCompletion(String completion) {
+ if (suggestions.any(
+ (CompletionSuggestion suggestion) => suggestion.completion == completion)) {
+ fail(
+ "Did not expect completion '$completion' but found:\n $suggestedCompletions");
+ }
+ }
+
+ runTest(LocationSpec spec, [Map<String, String> extraFiles]) {
+ super.setUp();
+ String content = spec.source;
+ addFile(testFile, content);
+ this.testCode = content;
+ completionOffset = spec.testLocation;
+ if (extraFiles != null) {
+ extraFiles.forEach((String fileName, String content) {
+ addFile(fileName, content);
+ });
+ }
+ return getSuggestions().then((_) {
+ try {
+ //expect(replacementOffset, equals(completionOffset));
+ //expect(replacementLength, equals(0));
+ for (String result in spec.positiveResults) {
+ assertHasCompletion(result);
+ }
+ for (String result in spec.negativeResults) {
+ assertHasNoCompletion(result);
+ }
+ } finally {
+ super.tearDown();
+ }
+ });
+ }
+
+ /**
+ * Generate a set of completion tests based on the given [originalSource].
+ *
+ * The source string has completion points embedded in it, which are
+ * identified by '!X' where X is a single character. Each X is matched to
+ * positive or negative results in the array of [validationStrings].
+ * Validation strings contain the name of a prediction with a two character
+ * prefix. The first character of the prefix corresponds to an X in the
+ * [originalSource]. The second character is either a '+' or a '-' indicating
+ * whether the string is a positive or negative result.
+ *
+ * The [originalSource] is the source for a completion test that contains
+ * completion points. The [validationStrings] are the positive and negative
+ * predictions.
+ */
+ static void buildTests(String baseName, String originalSource,
+ List<String> results, [Map<String, String> extraFiles]) {
+ List<LocationSpec> completionTests =
+ LocationSpec.from(originalSource, results);
+ completionTests.sort((LocationSpec first, LocationSpec second) {
+ return first.id.compareTo(second.id);
+ });
+ if (completionTests.isEmpty) {
+ test(baseName, () {
+ fail(
+ "Expected exclamation point ('!') within the source denoting the"
+ "position at which code completion should occur");
+ });
+ }
+ for (LocationSpec spec in completionTests) {
+ test("$baseName-${spec.id}", () {
+ CompletionTestCase test = new CompletionTestCase();
+ return test.runTest(spec, extraFiles);
+ });
+ }
+ }
+}
+
+/**
+ * A specification of the completion results expected at a given location.
+ */
+class LocationSpec {
+ String id;
+ int testLocation = -1;
+ List<String> positiveResults = <String>[];
+ List<String> negativeResults = <String>[];
+ String source;
+
+ LocationSpec(this.id);
+
+ /**
+ * Parse a set of tests from the given `originalSource`. Return a list of the
+ * specifications that were parsed.
+ *
+ * The source string has test locations embedded in it, which are identified
+ * by '!X' where X is a single character. Each X is matched to positive or
+ * negative results in the array of [validationStrings]. Validation strings
+ * contain the name of a prediction with a two character prefix. The first
+ * character of the prefix corresponds to an X in the [originalSource]. The
+ * second character is either a '+' or a '-' indicating whether the string is
+ * a positive or negative result. If logical not is needed in the source it
+ * can be represented by '!!'.
+ *
+ * The [originalSource] is the source for a test that contains test locations.
+ * The [validationStrings] are the positive and negative predictions.
+ */
+ static List<LocationSpec> from(String originalSource,
+ List<String> validationStrings) {
+ Map<String, LocationSpec> tests = new HashMap<String, LocationSpec>();
+ String modifiedSource = originalSource;
+ int modifiedPosition = 0;
+ while (true) {
+ int index = modifiedSource.indexOf('!', modifiedPosition);
+ if (index < 0) {
+ break;
+ }
+ int n = 1; // only delete one char for double-bangs
+ String id = modifiedSource.substring(index + 1, index + 2);
+ if (id != '!') {
+ n = 2;
+ LocationSpec test = new LocationSpec(id);
+ tests[id] = test;
+ test.testLocation = index;
+ } else {
+ modifiedPosition = index + 1;
+ }
+ modifiedSource =
+ modifiedSource.substring(0, index) + modifiedSource.substring(index + n);
+ }
+ if (modifiedSource == originalSource) {
+ throw new IllegalStateException("No tests in source: " + originalSource);
+ }
+ for (String result in validationStrings) {
+ if (result.length < 3) {
+ throw new IllegalStateException("Invalid location result: " + result);
+ }
+ String id = result.substring(0, 1);
+ String sign = result.substring(1, 2);
+ String value = result.substring(2);
+ LocationSpec test = tests[id];
+ if (test == null) {
+ throw new IllegalStateException(
+ "Invalid location result id: $id for: $result");
+ }
+ test.source = modifiedSource;
+ if (sign == '+') {
+ test.positiveResults.add(value);
+ } else if (sign == '-') {
+ test.negativeResults.add(value);
+ } else {
+ String err = "Invalid location result sign: $sign for: $result";
+ throw new IllegalStateException(err);
+ }
+ }
+ List<String> badPoints = <String>[];
+ List<String> badResults = <String>[];
+ for (LocationSpec test in tests.values) {
+ if (test.testLocation == -1) {
+ badPoints.add(test.id);
+ }
+ if (test.positiveResults.isEmpty && test.negativeResults.isEmpty) {
+ badResults.add(test.id);
+ }
+ }
+ if (!(badPoints.isEmpty && badResults.isEmpty)) {
+ StringBuffer err = new StringBuffer();
+ if (!badPoints.isEmpty) {
+ err.write("No test location for tests:");
+ for (String ch in badPoints) {
+ err
+ ..write(' ')
+ ..write(ch);
+ }
+ err.write(' ');
+ }
+ if (!badResults.isEmpty) {
+ err.write("No results for tests:");
+ for (String ch in badResults) {
+ err
+ ..write(' ')
+ ..write(ch);
+ }
+ }
+ throw new IllegalStateException(err.toString());
+ }
+ return tests.values.toList();
+ }
+}
« no previous file with comments | « pkg/analysis_server/test/completion_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698