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

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: Forgot to close IOSink. Rollback to File.writeAsString(). 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
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 new CoverageServer(targetFolder, targetPath, outPath).start()
32 .start()
33 .then((port) { 32 .then((port) {
34 var options = new Options(); 33 var options = new Options();
35 var targetArgs = ['http://127.0.0.1:$port/$targetName']; 34 var targetArgs = ['http://127.0.0.1:$port/$targetName'];
36 var dartExecutable = options.executable; 35 var dartExecutable = options.executable;
37 Process.start(dartExecutable, targetArgs).then((Process process) { 36 return Process.start(dartExecutable, targetArgs)
38 process.exitCode.then(exit); 37 .then((Process process) {
Bob Nystrom 2013/06/18 15:58:25 If you want, you can move this .then() call one le
scheglov 2013/06/18 16:36:11 Done.
39 // Redirect process streams. 38 process.exitCode.then(exit);
40 stdin.pipe(process.stdin); 39 // Redirect process streams.
41 process.stdout.pipe(stdout); 40 stdin.pipe(process.stdin);
42 process.stderr.pipe(stderr); 41 process.stdout.pipe(stdout);
43 }); 42 process.stderr.pipe(stderr);
43 });
44 }).catchError((e) {
45 log.severe('Error starting $targetPath. $e');
44 }); 46 });
45 } 47 }
46 48
47 49
48 /// Abstract server to listen requests and serve files, may be rewriting them. 50 /// Abstract server to listen requests and serve files, may be rewriting them.
49 abstract class RewriteServer { 51 abstract class RewriteServer {
50 final String basePath; 52 final String basePath;
51 int port; 53 int port;
52 54
53 RewriteServer(this.basePath); 55 RewriteServer(this.basePath);
54 56
55 /// Runs the HTTP server on the ephemeral port and returns [Future] with it. 57 /// Runs the HTTP server on the ephemeral port and returns [Future] with it.
56 Future<int> start() { 58 Future<int> start() {
57 return HttpServer.bind('127.0.0.1', 0).then((server) { 59 return HttpServer.bind('127.0.0.1', 0).then((server) {
58 port = server.port; 60 port = server.port;
59 log.info('RewriteServer is listening at: $port.'); 61 log.info('RewriteServer is listening at: $port.');
60 server.listen((request) { 62 server.listen((request) {
61 if (request.method == 'GET') { 63 if (request.method == 'GET') {
62 handleGetRequest(request); 64 handleGetRequest(request);
63 } 65 }
64 if (request.method == 'POST') { 66 if (request.method == 'POST') {
65 handlePostRequest(request); 67 handlePostRequest(request);
66 } 68 }
67 }); 69 });
68 return port; 70 return port;
69 }); 71 });
70 } 72 }
71 73
72 handlePostRequest(HttpRequest request); 74 void handlePostRequest(HttpRequest request);
73 75
74 handleGetRequest(HttpRequest request) { 76 void handleGetRequest(HttpRequest request) {
75 var response = request.response; 77 var response = request.response;
76 // Prepare path. 78 // Prepare path.
77 var path = basePath + '/' + request.uri.path; 79 var path = getFilePath(request.uri);
78 path = pathos.normalize(path);
79 log.info('[$path] Requested.'); 80 log.info('[$path] Requested.');
80 // May be serve using just path. 81 // May be serve using just path.
81 { 82 {
82 var content = rewritePathContent(path); 83 var content = rewritePathContent(path);
83 if (content != null) { 84 if (content != null) {
84 log.info('[$path] Request served by path.'); 85 log.info('[$path] Request served by path.');
85 response.write(content); 86 response.write(content);
86 response.close(); 87 response.close();
87 return; 88 return;
88 } 89 }
89 } 90 }
90 // Serve from file. 91 // Serve from file.
91 log.info('[$path] Serving file.'); 92 log.info('[$path] Serving file.');
92 var file = new File(path); 93 var file = new File(path);
93 file.exists().then((found) { 94 file.exists().then((found) {
94 if (found) { 95 if (found) {
95 // May be this files should be sent as is. 96 // May be this files should be sent as is.
96 if (!shouldRewriteFile(path)) { 97 if (!shouldRewriteFile(path)) {
97 sendFile(request, file); 98 return sendFile(request, file);
98 return;
99 } 99 }
100 // Rewrite content of the file. 100 // Rewrite content of the file.
101 file.readAsString().then((content) { 101 return file.readAsString().then((content) {
102 log.finest('[$path] Done reading ${content.length} characters.'); 102 log.finest('[$path] Done reading ${content.length} characters.');
103 content = rewriteFileContent(path, content); 103 content = rewriteFileContent(path, content);
104 log.fine('[$path] Rewritten.'); 104 log.fine('[$path] Rewritten.');
105 response.write(content); 105 response.write(content);
106 response.close(); 106 return response.close();
107 }); 107 });
108 } else { 108 } else {
109 log.severe('[$path] File not found.'); 109 log.severe('[$path] File not found.');
110 response.statusCode = HttpStatus.NOT_FOUND; 110 response.statusCode = HttpStatus.NOT_FOUND;
111 response.close(); 111 return response.close();
112 } 112 }
113 }).catchError((e) {
114 log.severe('[$path] $e.');
115 response.statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
116 return response.close();
113 }); 117 });
114 } 118 }
115 119
116 void sendFile(HttpRequest request, File file) { 120 String getFilePath(Uri uri) {
121 var path = uri.path;
122 // URIs usually have leading '/'.
123 if (path.startsWith('/')) path = path.substring(1);
124 // Convert from URI to system.
125 var parts = new pathos.Builder(style: pathos.Style.url).split(path);
126 path = pathos.joinAll(parts);
Bob Nystrom 2013/06/18 15:58:25 The "Builder" name is a bit confusing in pathos, b
scheglov 2013/06/18 16:36:11 Hm... I use URL style to convert URI to path parts
Bob Nystrom 2013/06/18 17:22:27 Oh, sorry, right. I wasn't reading the code closel
127 // Prepend with base path.
128 path = pathos.join(basePath, path);
129 return pathos.normalize(path);
130 }
131
132 Future sendFile(HttpRequest request, File file) {
117 file.fullPath().then((fullPath) { 133 file.fullPath().then((fullPath) {
118 file.openRead() 134 return file.openRead().pipe(request.response);
119 .pipe(request.response)
120 .catchError((e) {});
121 }); 135 });
122 } 136 }
123 137
124 bool shouldRewriteFile(String path); 138 bool shouldRewriteFile(String path);
125 139
126 /// Subclasses implement this method to rewrite the provided [code] of the 140 /// Subclasses implement this method to rewrite the provided [code] of the
127 /// file with [path]. Returns some content or `null` if file content 141 /// file with [path]. Returns some content or `null` if file content
128 /// should be requested. 142 /// should be requested.
129 String rewritePathContent(String path); 143 String rewritePathContent(String path);
130 144
131 /// Subclasses implement this method to rewrite the provided [code] of the 145 /// Subclasses implement this method to rewrite the provided [code] of the
132 /// file with [path]. 146 /// file with [path].
133 String rewriteFileContent(String path, String code); 147 String rewriteFileContent(String path, String code);
134 } 148 }
135 149
136 150
151 /// Here `CCC` means 'code coverage configuration'.
152 const TEST_UNIT_CCC = '''
153 class __CCC extends __cc_ut.Configuration {
154 void onDone(bool success) {
155 __cc.postStatistics();
156 super.onDone(success);
157 }
158 }''';
159
160 const TEST_UNIT_CCC_SET = '__cc_ut.unittestConfiguration = new __CCC();';
161
162
137 /// Server that rewrites Dart code so that it reports execution of statements 163 /// Server that rewrites Dart code so that it reports execution of statements
138 /// and other nodes. 164 /// and other nodes.
139 class CoverageServer extends RewriteServer { 165 class CoverageServer extends RewriteServer {
140 final appInfo = new AppInfo(); 166 final appInfo = new AppInfo();
141 final String targetPath; 167 final String targetPath;
142 final String outPath; 168 final String outPath;
143 169
144 CoverageServer(String basePath, this.targetPath, this.outPath) 170 CoverageServer(String basePath, this.targetPath, this.outPath)
145 : super(basePath); 171 : super(basePath);
146 172
147 void handlePostRequest(HttpRequest request) { 173 void handlePostRequest(HttpRequest request) {
148 var id = 0; 174 var id = 0;
149 var executedIds = new Set<int>(); 175 var executedIds = new Set<int>();
150 request.listen((data) { 176 request.listen((data) {
151 log.fine('Received statistics, ${data.length} bytes.'); 177 log.fine('Received statistics, ${data.length} bytes.');
152 while (true) { 178 while (true) {
153 var listIndex = id ~/ 8; 179 var listIndex = id ~/ 8;
154 if (listIndex >= data.length) break; 180 if (listIndex >= data.length) break;
155 var bitIndex = id % 8; 181 var bitIndex = id % 8;
156 if ((data[listIndex] & (1 << bitIndex)) != 0) { 182 if ((data[listIndex] & (1 << bitIndex)) != 0) {
157 executedIds.add(id); 183 executedIds.add(id);
158 } 184 }
159 id++; 185 id++;
160 } 186 }
161 }).onDone(() { 187 }).onDone(() {
162 log.fine('Received all statistics.'); 188 log.fine('Received all statistics.');
163 var sb = new StringBuffer(); 189 var buffer = new StringBuffer();
164 appInfo.write(sb, executedIds); 190 appInfo.write(buffer, executedIds);
165 new File(outPath).writeAsString(sb.toString()); 191 new File(outPath).writeAsString(buffer.toString()).then((_) {
166 log.fine('Results are written to $outPath.'); 192 return request.response.close();
167 request.response.close(); 193 }).catchError((e) {
194 log.severe('Error in receiving statistics $e.');
195 return request.response.close();
196 });
168 }); 197 });
169 } 198 }
170 199
171 String rewritePathContent(String path) { 200 String rewritePathContent(String path) {
172 if (path.endsWith('__coverage_lib.dart')) { 201 if (path.endsWith('__coverage_lib.dart')) {
173 String implPath = pathos.joinAll([ 202 String implPath = pathos.joinAll([
174 pathos.dirname(new Options().script), 203 pathos.dirname(new Options().script),
175 '..', 'lib', 'src', 'services', 'runtime', 'coverage', 204 '..', 'lib', 'src', 'services', 'runtime', 'coverage',
176 'coverage_lib.dart']); 205 'coverage_lib.dart']);
177 var content = new File(implPath).readAsStringSync(); 206 var content = new File(implPath).readAsStringSync();
178 content = content.replaceAll('0; // replaced during rewrite', '$port;'); 207 return content.replaceAll('0; // replaced during rewrite', '$port;');
179 return content;
180 } 208 }
181 return null; 209 return null;
182 } 210 }
183 211
184 bool shouldRewriteFile(String path) { 212 bool shouldRewriteFile(String path) {
185 if (pathos.extension(path).toLowerCase() != '.dart') return false; 213 if (pathos.extension(path).toLowerCase() != '.dart') return false;
186 // Rewrite target itself, only to send statistics. 214 // Rewrite target itself, only to send statistics.
187 if (path == targetPath) { 215 if (path == targetPath) {
188 return true; 216 return true;
189 } 217 }
190 // TODO(scheglov) use configuration 218 // TODO(scheglov) use configuration
191 if (path.contains('/packages/analyzer_experimental/')) { 219 return path.contains('/packages/analyzer_experimental/');
192 return true;
193 }
194 return false;
195 } 220 }
196 221
197 String rewriteFileContent(String path, String code) { 222 String rewriteFileContent(String path, String code) {
198 var unit = _parseCode(code); 223 var unit = _parseCode(code);
199 log.finest('[$path] Parsed.'); 224 log.finest('[$path] Parsed.');
200 var injector = new CodeInjector(code); 225 var injector = new CodeInjector(code);
201 // Inject imports. 226 // Inject imports.
202 var directives = unit.directives; 227 var directives = unit.directives;
203 if (directives.isNotEmpty && directives[0] is LibraryDirective) { 228 if (directives.isNotEmpty && directives[0] is LibraryDirective) {
204 injector.inject(directives[0].end, 229 injector.inject(directives[0].end,
205 'import "package:unittest/unittest.dart" as __cc_ut;' 230 'import "package:unittest/unittest.dart" as __cc_ut;'
206 'import "http://127.0.0.1:$port/__coverage_lib.dart" as __cc;'); 231 'import "http://127.0.0.1:$port/__coverage_lib.dart" as __cc;');
207 } 232 }
208 // Inject statistics sender. 233 // Inject statistics sender.
209 var isTargetScript = path == targetPath; 234 var isTargetScript = path == targetPath;
210 if (isTargetScript) { 235 if (isTargetScript) {
211 for (var node in unit.declarations) { 236 for (var node in unit.declarations) {
212 if (node is FunctionDeclaration) { 237 if (node is FunctionDeclaration) {
213 var body = node.functionExpression.body; 238 var body = node.functionExpression.body;
214 if (node.name.name == 'main' && body is BlockFunctionBody) { 239 if (node.name.name == 'main' && body is BlockFunctionBody) {
215 injector.inject(node.offset, 240 injector.inject(node.offset, TEST_UNIT_CCC);
216 'class __CCC extends __cc_ut.Configuration {' 241 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 } 242 }
226 } 243 }
227 } 244 }
228 } 245 }
229 // Inject touch() invocations. 246 // Inject touch() invocations.
230 if (!isTargetScript) { 247 if (!isTargetScript) {
231 appInfo.enterUnit(path, code); 248 appInfo.enterUnit(path, code);
232 unit.accept(new InsertTouchInvocationsVisitor(appInfo, injector)); 249 unit.accept(new InsertTouchInvocationsVisitor(appInfo, injector));
233 } 250 }
234 // Done. 251 // Done.
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 var lastOffset = 0; 340 var lastOffset = 0;
324 offsetFragmentMap.forEach((offset, fragment) { 341 offsetFragmentMap.forEach((offset, fragment) {
325 sb.write(_code.substring(lastOffset, offset)); 342 sb.write(_code.substring(lastOffset, offset));
326 sb.write(fragment); 343 sb.write(fragment);
327 lastOffset = offset; 344 lastOffset = offset;
328 }); 345 });
329 sb.write(_code.substring(lastOffset, _code.length)); 346 sb.write(_code.substring(lastOffset, _code.length));
330 return sb.toString(); 347 return sb.toString();
331 } 348 }
332 } 349 }
OLDNEW
« pkg/analyzer_experimental/bin/coverage.dart ('K') | « pkg/analyzer_experimental/bin/coverage.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698