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

Side by Side Diff: pkg/analyzer_experimental/lib/src/services/runtime/coverage/coverage_impl.dart

Issue 16885003: Fixes for forgotten review comments. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Flatten futures hierarchy Created 7 years, 6 months 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/analyzer_experimental/bin/coverage.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// A library for code coverage support for Dart. 5 /// A library for code coverage support for Dart.
6 library runtime.coverage.impl; 6 library runtime.coverage.impl;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:collection' show SplayTreeMap; 9 import 'dart:collection' show SplayTreeMap;
10 import 'dart:io'; 10 import 'dart:io';
(...skipping 10 matching lines...) Expand all
21 import '../log.dart' as log; 21 import '../log.dart' as log;
22 import 'models.dart'; 22 import 'models.dart';
23 import 'utils.dart'; 23 import 'utils.dart';
24 24
25 /// Run the [targetPath] with code coverage rewriting. 25 /// Run the [targetPath] with code coverage rewriting.
26 /// Redirects stdandard process streams. 26 /// Redirects stdandard process streams.
27 /// On process exit dumps coverage statistics into the [outPath]. 27 /// On process exit dumps coverage statistics into the [outPath].
28 void runServerApplication(String targetPath, String outPath) { 28 void runServerApplication(String targetPath, String outPath) {
29 var targetFolder = pathos.dirname(targetPath); 29 var targetFolder = pathos.dirname(targetPath);
30 var targetName = pathos.basename(targetPath); 30 var targetName = pathos.basename(targetPath);
31 new CoverageServer(targetFolder, targetPath, outPath) 31 var server = new CoverageServer(targetFolder, targetPath, outPath);
32 .start() 32 server.start().then((port) {
33 .then((port) { 33 var options = new Options();
34 var options = new Options(); 34 var targetArgs = ['http://127.0.0.1:$port/$targetName'];
35 var targetArgs = ['http://127.0.0.1:$port/$targetName']; 35 var dartExecutable = options.executable;
36 var dartExecutable = options.executable; 36 return Process.start(dartExecutable, targetArgs);
37 Process.start(dartExecutable, targetArgs).then((Process process) { 37 }).then((process) {
38 process.exitCode.then(exit); 38 stdin.pipe(process.stdin);
39 // Redirect process streams. 39 process.stdout.pipe(stdout);
40 stdin.pipe(process.stdin); 40 process.stderr.pipe(stderr);
41 process.stdout.pipe(stdout); 41 return process.exitCode;
42 process.stderr.pipe(stderr); 42 }).then(exit).catchError((e) {
43 }); 43 log.severe('Error starting $targetPath. $e');
44 }); 44 });
45 } 45 }
46 46
47 47
48 /// Abstract server to listen requests and serve files, may be rewriting them. 48 /// Abstract server to listen requests and serve files, may be rewriting them.
49 abstract class RewriteServer { 49 abstract class RewriteServer {
50 final String basePath; 50 final String basePath;
51 int port; 51 int port;
52 52
53 RewriteServer(this.basePath); 53 RewriteServer(this.basePath);
54 54
55 /// Runs the HTTP server on the ephemeral port and returns [Future] with it. 55 /// Runs the HTTP server on the ephemeral port and returns [Future] with it.
56 Future<int> start() { 56 Future<int> start() {
57 return HttpServer.bind('127.0.0.1', 0).then((server) { 57 return HttpServer.bind('127.0.0.1', 0).then((server) {
58 port = server.port; 58 port = server.port;
59 log.info('RewriteServer is listening at: $port.'); 59 log.info('RewriteServer is listening at: $port.');
60 server.listen((request) { 60 server.listen((request) {
61 if (request.method == 'GET') { 61 if (request.method == 'GET') {
62 handleGetRequest(request); 62 handleGetRequest(request);
63 } 63 }
64 if (request.method == 'POST') { 64 if (request.method == 'POST') {
65 handlePostRequest(request); 65 handlePostRequest(request);
66 } 66 }
67 }); 67 });
68 return port; 68 return port;
69 }); 69 });
70 } 70 }
71 71
72 handlePostRequest(HttpRequest request); 72 void handlePostRequest(HttpRequest request);
73 73
74 handleGetRequest(HttpRequest request) { 74 void handleGetRequest(HttpRequest request) {
75 var response = request.response; 75 var response = request.response;
76 // Prepare path. 76 // Prepare path.
77 var path = basePath + '/' + request.uri.path; 77 var path = getFilePath(request.uri);
78 path = pathos.normalize(path);
79 log.info('[$path] Requested.'); 78 log.info('[$path] Requested.');
80 // May be serve using just path. 79 // May be serve using just path.
81 { 80 {
82 var content = rewritePathContent(path); 81 var content = rewritePathContent(path);
83 if (content != null) { 82 if (content != null) {
84 log.info('[$path] Request served by path.'); 83 log.info('[$path] Request served by path.');
85 response.write(content); 84 response.write(content);
86 response.close(); 85 response.close();
87 return; 86 return;
88 } 87 }
89 } 88 }
90 // Serve from file. 89 // Serve from file.
91 log.info('[$path] Serving file.'); 90 log.info('[$path] Serving file.');
92 var file = new File(path); 91 var file = new File(path);
93 file.exists().then((found) { 92 file.exists().then((found) {
94 if (found) { 93 if (found) {
95 // May be this files should be sent as is. 94 // May be this files should be sent as is.
96 if (!shouldRewriteFile(path)) { 95 if (!shouldRewriteFile(path)) {
97 sendFile(request, file); 96 return sendFile(request, file);
98 return;
99 } 97 }
100 // Rewrite content of the file. 98 // Rewrite content of the file.
101 file.readAsString().then((content) { 99 return file.readAsString().then((content) {
102 log.finest('[$path] Done reading ${content.length} characters.'); 100 log.finest('[$path] Done reading ${content.length} characters.');
103 content = rewriteFileContent(path, content); 101 content = rewriteFileContent(path, content);
104 log.fine('[$path] Rewritten.'); 102 log.fine('[$path] Rewritten.');
105 response.write(content); 103 response.write(content);
106 response.close(); 104 return response.close();
107 }); 105 });
108 } else { 106 } else {
109 log.severe('[$path] File not found.'); 107 log.severe('[$path] File not found.');
110 response.statusCode = HttpStatus.NOT_FOUND; 108 response.statusCode = HttpStatus.NOT_FOUND;
111 response.close(); 109 return response.close();
112 } 110 }
111 }).catchError((e) {
112 log.severe('[$path] $e.');
113 response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
114 return response.close();
113 }); 115 });
114 } 116 }
115 117
116 void sendFile(HttpRequest request, File file) { 118 String getFilePath(Uri uri) {
119 var path = uri.path;
120 path = pathos.joinAll(uri.pathSegments);
121 path = pathos.join(basePath, path);
122 return pathos.normalize(path);
123 }
124
125 Future sendFile(HttpRequest request, File file) {
117 file.fullPath().then((fullPath) { 126 file.fullPath().then((fullPath) {
118 file.openRead() 127 return file.openRead().pipe(request.response);
119 .pipe(request.response)
120 .catchError((e) {});
121 }); 128 });
122 } 129 }
123 130
124 bool shouldRewriteFile(String path); 131 bool shouldRewriteFile(String path);
125 132
126 /// Subclasses implement this method to rewrite the provided [code] of the 133 /// Subclasses implement this method to rewrite the provided [code] of the
127 /// file with [path]. Returns some content or `null` if file content 134 /// file with [path]. Returns some content or `null` if file content
128 /// should be requested. 135 /// should be requested.
129 String rewritePathContent(String path); 136 String rewritePathContent(String path);
130 137
131 /// Subclasses implement this method to rewrite the provided [code] of the 138 /// Subclasses implement this method to rewrite the provided [code] of the
132 /// file with [path]. 139 /// file with [path].
133 String rewriteFileContent(String path, String code); 140 String rewriteFileContent(String path, String code);
134 } 141 }
135 142
136 143
144 /// Here `CCC` means 'code coverage configuration'.
145 const TEST_UNIT_CCC = '''
146 class __CCC extends __cc_ut.Configuration {
147 void onDone(bool success) {
148 __cc.postStatistics();
149 super.onDone(success);
150 }
151 }''';
152
153 const TEST_UNIT_CCC_SET = '__cc_ut.unittestConfiguration = new __CCC();';
154
155
137 /// Server that rewrites Dart code so that it reports execution of statements 156 /// Server that rewrites Dart code so that it reports execution of statements
138 /// and other nodes. 157 /// and other nodes.
139 class CoverageServer extends RewriteServer { 158 class CoverageServer extends RewriteServer {
140 final appInfo = new AppInfo(); 159 final appInfo = new AppInfo();
141 final String targetPath; 160 final String targetPath;
142 final String outPath; 161 final String outPath;
143 162
144 CoverageServer(String basePath, this.targetPath, this.outPath) 163 CoverageServer(String basePath, this.targetPath, this.outPath)
145 : super(basePath); 164 : super(basePath);
146 165
147 void handlePostRequest(HttpRequest request) { 166 void handlePostRequest(HttpRequest request) {
148 var id = 0; 167 var id = 0;
149 var executedIds = new Set<int>(); 168 var executedIds = new Set<int>();
150 request.listen((data) { 169 request.listen((data) {
151 log.fine('Received statistics, ${data.length} bytes.'); 170 log.fine('Received statistics, ${data.length} bytes.');
152 while (true) { 171 while (true) {
153 var listIndex = id ~/ 8; 172 var listIndex = id ~/ 8;
154 if (listIndex >= data.length) break; 173 if (listIndex >= data.length) break;
155 var bitIndex = id % 8; 174 var bitIndex = id % 8;
156 if ((data[listIndex] & (1 << bitIndex)) != 0) { 175 if ((data[listIndex] & (1 << bitIndex)) != 0) {
157 executedIds.add(id); 176 executedIds.add(id);
158 } 177 }
159 id++; 178 id++;
160 } 179 }
161 }).onDone(() { 180 }).onDone(() {
162 log.fine('Received all statistics.'); 181 log.fine('Received all statistics.');
163 var sb = new StringBuffer(); 182 var buffer = new StringBuffer();
164 appInfo.write(sb, executedIds); 183 appInfo.write(buffer, executedIds);
165 new File(outPath).writeAsString(sb.toString()); 184 new File(outPath).writeAsString(buffer.toString()).then((_) {
166 log.fine('Results are written to $outPath.'); 185 return request.response.close();
167 request.response.close(); 186 }).catchError((e) {
187 log.severe('Error in receiving statistics $e.');
188 return request.response.close();
189 });
168 }); 190 });
169 } 191 }
170 192
171 String rewritePathContent(String path) { 193 String rewritePathContent(String path) {
172 if (path.endsWith('__coverage_lib.dart')) { 194 if (path.endsWith('__coverage_lib.dart')) {
173 String implPath = pathos.joinAll([ 195 String implPath = pathos.joinAll([
174 pathos.dirname(new Options().script), 196 pathos.dirname(new Options().script),
175 '..', 'lib', 'src', 'services', 'runtime', 'coverage', 197 '..', 'lib', 'src', 'services', 'runtime', 'coverage',
176 'coverage_lib.dart']); 198 'coverage_lib.dart']);
177 var content = new File(implPath).readAsStringSync(); 199 var content = new File(implPath).readAsStringSync();
178 content = content.replaceAll('0; // replaced during rewrite', '$port;'); 200 return content.replaceAll('0; // replaced during rewrite', '$port;');
179 return content;
180 } 201 }
181 return null; 202 return null;
182 } 203 }
183 204
184 bool shouldRewriteFile(String path) { 205 bool shouldRewriteFile(String path) {
185 if (pathos.extension(path).toLowerCase() != '.dart') return false; 206 if (pathos.extension(path).toLowerCase() != '.dart') return false;
186 // Rewrite target itself, only to send statistics. 207 // Rewrite target itself, only to send statistics.
187 if (path == targetPath) { 208 if (path == targetPath) {
188 return true; 209 return true;
189 } 210 }
190 // TODO(scheglov) use configuration 211 // TODO(scheglov) use configuration
191 if (path.contains('/packages/analyzer_experimental/')) { 212 return path.contains('/packages/analyzer_experimental/');
192 return true;
193 }
194 return false;
195 } 213 }
196 214
197 String rewriteFileContent(String path, String code) { 215 String rewriteFileContent(String path, String code) {
198 var unit = _parseCode(code); 216 var unit = _parseCode(code);
199 log.finest('[$path] Parsed.'); 217 log.finest('[$path] Parsed.');
200 var injector = new CodeInjector(code); 218 var injector = new CodeInjector(code);
201 // Inject imports. 219 // Inject imports.
202 var directives = unit.directives; 220 var directives = unit.directives;
203 if (directives.isNotEmpty && directives[0] is LibraryDirective) { 221 if (directives.isNotEmpty && directives[0] is LibraryDirective) {
204 injector.inject(directives[0].end, 222 injector.inject(directives[0].end,
205 'import "package:unittest/unittest.dart" as __cc_ut;' 223 'import "package:unittest/unittest.dart" as __cc_ut;'
206 'import "http://127.0.0.1:$port/__coverage_lib.dart" as __cc;'); 224 'import "http://127.0.0.1:$port/__coverage_lib.dart" as __cc;');
207 } 225 }
208 // Inject statistics sender. 226 // Inject statistics sender.
209 var isTargetScript = path == targetPath; 227 var isTargetScript = path == targetPath;
210 if (isTargetScript) { 228 if (isTargetScript) {
211 for (var node in unit.declarations) { 229 for (var node in unit.declarations) {
212 if (node is FunctionDeclaration) { 230 if (node is FunctionDeclaration) {
213 var body = node.functionExpression.body; 231 var body = node.functionExpression.body;
214 if (node.name.name == 'main' && body is BlockFunctionBody) { 232 if (node.name.name == 'main' && body is BlockFunctionBody) {
215 injector.inject(node.offset, 233 injector.inject(node.offset, TEST_UNIT_CCC);
216 'class __CCC extends __cc_ut.Configuration {' 234 injector.inject(body.offset + 1, TEST_UNIT_CCC_SET);
217 ' void onDone(bool success) {'
218 ' __cc.postStatistics();'
219 ' super.onDone(success);'
220 ' }'
221 '}');
222 injector.inject(
223 body.offset + 1,
224 '__cc_ut.unittestConfiguration = new __CCC();');
225 } 235 }
226 } 236 }
227 } 237 }
228 } 238 }
229 // Inject touch() invocations. 239 // Inject touch() invocations.
230 if (!isTargetScript) { 240 if (!isTargetScript) {
231 appInfo.enterUnit(path, code); 241 appInfo.enterUnit(path, code);
232 unit.accept(new InsertTouchInvocationsVisitor(appInfo, injector)); 242 unit.accept(new InsertTouchInvocationsVisitor(appInfo, injector));
233 } 243 }
234 // Done. 244 // Done.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 var lastOffset = 0; 333 var lastOffset = 0;
324 offsetFragmentMap.forEach((offset, fragment) { 334 offsetFragmentMap.forEach((offset, fragment) {
325 sb.write(_code.substring(lastOffset, offset)); 335 sb.write(_code.substring(lastOffset, offset));
326 sb.write(fragment); 336 sb.write(fragment);
327 lastOffset = offset; 337 lastOffset = offset;
328 }); 338 });
329 sb.write(_code.substring(lastOffset, _code.length)); 339 sb.write(_code.substring(lastOffset, _code.length));
330 return sb.toString(); 340 return sb.toString();
331 } 341 }
332 } 342 }
OLDNEW
« no previous file with comments | « pkg/analyzer_experimental/bin/coverage.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698