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

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

Issue 16964008: Code coverage, something is working now. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 /// A library for code coverage support for Dart.
6 library runtime.coverage_impl;
7
8 import "dart:io";
9
10 import "package:logging/logging.dart" as log;
11 import "package:pathos/path.dart" as po;
12
13 import 'package:analyzer_experimental/src/generated/source.dart' show Source;
14 import 'package:analyzer_experimental/src/generated/scanner.dart' show StringSca nner;
15 import 'package:analyzer_experimental/src/generated/parser.dart' show Parser;
16 import 'package:analyzer_experimental/src/generated/ast.dart';
17 import 'package:analyzer_experimental/src/generated/engine.dart' show RecordingE rrorListener;
18
19
20 log.Logger logger = log.Logger.root;
21
22 /// Abstract server that listens requests and serves files, may be rewriting the m.
23 abstract class RewriteServer {
24 String _basePath;
25 RewriteServer(this._basePath);
26 void start() {
27 HttpServer.bind("127.0.0.1", 3445).then((HttpServer server) {
28 logger.info('RewriteServer is listening at: ${server.port}.');
29 server.listen((HttpRequest request) {
30 var response = request.response;
31 // Prepare path.
32 var path = _basePath + '/' + request.uri.path;
33 path = po.normalize(path);
34 logger.info('[$path] Requested.');
35 // May be serve using just path.
36 {
37 String content = rewritePathContent(path);
38 if (content != null) {
39 logger.info('[$path] Request served by path.');
40 response.write(content);
41 response.close();
42 return;
43 }
44 }
45 // Serve from file.
46 logger.info('[$path] Serving file.');
47 var file = new File(path);
48 file.exists().then((bool found) {
49 if (found) {
50 logger.finest('[$path] Found file.');
51 file.readAsString().then((String content) {
52 logger.finest('[$path] Got file content.');
53 var sw = new Stopwatch();
54 sw.start();
55 try {
56 content = rewriteFileContent(path, content);
57 } finally {
58 sw.stop();
59 logger.fine('[$path] Rewritten in ${sw.elapsedMilliseconds} ms.' );
60 }
61 response.write(content);
62 response.close();
63 });
64 } else {
65 logger.severe('[$path] File not found.');
66 response.statusCode = HttpStatus.NOT_FOUND;
67 response.close();
68 }
69 });
70 });
71 });
72 }
73
74 /// Subclasses implement this method to rewrite the provided [code] of the fil e with [path].
75 /// Returns some content or `null` if file content should be requested.
76 String rewritePathContent(String path);
77
78 /// Subclasses implement this method to rewrite the provided [code] of the fil e with [path].
79 String rewriteFileContent(String path, String code);
80 }
81
82 /// Server that rewrites Dart code so that it reports execution of statements an d other nodes.
83 class CoverageServer extends RewriteServer {
84 CoverageServer(String basePath) : super(basePath);
85
86 String rewritePathContent(String path) {
87 if (path.endsWith('__coverage_impl.dart')) {
88 String implPath = po.joinAll([
89 po.dirname(new Options().script),
90 '..', 'lib', 'src', 'services', 'runtime', 'coverage_lib.dart']);
91 return new File(implPath).readAsStringSync();
92 }
93 return null;
94 }
95
96 String rewriteFileContent(String path, String code) {
97 if (po.extension(path).toLowerCase() != '.dart') return code;
98 if (path.contains('packages')) return code;
99 var unit = _parseCode(code);
100 var injector = new StringInjector(code);
101 // Inject coverage library import.
102 var directives = unit.directives;
103 if (directives.isNotEmpty && directives[0] is LibraryDirective) {
104 injector.inject(directives[0].end, 'import "__coverage_impl.dart" as __cc; ');
105 } else {
106 throw new Exception('Only single library coverage is implemented.');
107 }
108 // Insert touch() invocations.
109 unit.accept(new InsertTouchInvocationsVisitor(injector));
110 // Done.
111 code = injector.code;
112 logger.finest('[$path] Rewritten content\n$code');
113 return code;
114 }
115
116 CompilationUnit _parseCode(String code) {
117 var source = null;
118 var errorListener = new RecordingErrorListener();
119 var parser = new Parser(source, errorListener);
120 var scanner = new StringScanner(source, code, errorListener);
121 var token = scanner.tokenize();
122 return parser.parseCompilationUnit(token);
123 }
124 }
125
126 /// The visitor that inserts `touch` method invocations.
127 class InsertTouchInvocationsVisitor extends GeneralizingASTVisitor {
128 StringInjector injector;
129 InsertTouchInvocationsVisitor(this.injector);
130 visitStatement(Statement node) {
131 super.visitStatement(node);
132 var offset = node.end;
133 if (node is Block) {
134 offset--;
135 }
136 if (node is Block && node.parent is BlockFunctionBody) return null;
137 injector.inject(offset, '__cc.touch(${node.offset});');
138 return null;
139 }
140 }
141
142 /// Helper for injecting fragments into some existing [String].
143 class StringInjector {
144 String code;
145 int _lastOffset = -1;
146 int _delta = 0;
147 StringInjector(this.code);
148 void inject(int offset, String fragment) {
149 if (offset < _lastOffset) {
150 throw new ArgumentError('Only forward inserts are supported, was $_lastOff set given $offset');
151 }
152 _lastOffset = offset;
153 offset += _delta;
154 code = code.substring(0, offset) + fragment + code.substring(offset);
155 _delta += fragment.length;
156 }
157 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698