| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dev_compiler.test.dependency_graph_test; | 5 library dev_compiler.test.dependency_graph_test; |
| 6 | 6 |
| 7 import 'package:analyzer/file_system/file_system.dart'; |
| 8 import 'package:analyzer/file_system/memory_file_system.dart'; |
| 9 import 'package:analyzer/src/generated/source.dart'; |
| 7 import 'package:unittest/unittest.dart'; | 10 import 'package:unittest/unittest.dart'; |
| 8 | 11 |
| 9 import 'package:dev_compiler/src/checker/dart_sdk.dart' | 12 import 'package:dev_compiler/src/checker/dart_sdk.dart' |
| 10 show mockSdkSources, dartSdkDirectory; | 13 show mockSdkSources, dartSdkDirectory; |
| 11 import 'package:dev_compiler/src/in_memory.dart'; | |
| 12 import 'package:dev_compiler/src/options.dart'; | 14 import 'package:dev_compiler/src/options.dart'; |
| 13 import 'package:dev_compiler/src/checker/resolver.dart'; | 15 import 'package:dev_compiler/src/checker/resolver.dart'; |
| 14 import 'package:dev_compiler/src/dependency_graph.dart'; | 16 import 'package:dev_compiler/src/dependency_graph.dart'; |
| 15 import 'package:dev_compiler/src/report.dart'; | 17 import 'package:dev_compiler/src/report.dart'; |
| 18 import 'package:dev_compiler/src/testing.dart'; |
| 16 import 'package:path/path.dart' as path; | 19 import 'package:path/path.dart' as path; |
| 17 | 20 |
| 18 import 'test_util.dart'; | 21 import 'test_util.dart'; |
| 19 | 22 |
| 20 void main() { | 23 void main() { |
| 21 configureTest(); | 24 configureTest(); |
| 22 | 25 |
| 23 var options = new CompilerOptions(runtimeDir: '/dev_compiler_runtime/'); | 26 var options = new CompilerOptions(runtimeDir: '/dev_compiler_runtime/'); |
| 24 var testUriResolver; | 27 MemoryResourceProvider testResourceProvider; |
| 28 ResourceUriResolver testUriResolver; |
| 25 var context; | 29 var context; |
| 26 var graph; | 30 var graph; |
| 27 | 31 |
| 28 /// Initial values for test files | 32 /// Initial values for test files |
| 29 var testFiles = { | 33 var testFiles = { |
| 30 '/index1.html': ''' | 34 '/index1.html': ''' |
| 31 <script src="foo.js"></script> | 35 <script src="foo.js"></script> |
| 32 ''', | 36 ''', |
| 33 '/index2.html': ''' | 37 '/index2.html': ''' |
| 34 <script type="application/dart" src="a1.dart"></script> | 38 <script type="application/dart" src="a1.dart"></script> |
| (...skipping 19 matching lines...) Expand all Loading... |
| 54 '/a8.dart': 'library a8; import "a8.dart";', | 58 '/a8.dart': 'library a8; import "a8.dart";', |
| 55 '/a9.dart': 'library a9; import "a8.dart";', | 59 '/a9.dart': 'library a9; import "a8.dart";', |
| 56 '/a10.dart': 'library a10;', | 60 '/a10.dart': 'library a10;', |
| 57 }; | 61 }; |
| 58 | 62 |
| 59 nodeOf(String filepath) => graph.nodeFromUri(new Uri.file(filepath)); | 63 nodeOf(String filepath) => graph.nodeFromUri(new Uri.file(filepath)); |
| 60 | 64 |
| 61 setUp(() { | 65 setUp(() { |
| 62 /// We completely reset the TestUriResolver to avoid interference between | 66 /// We completely reset the TestUriResolver to avoid interference between |
| 63 /// tests (since some tests modify the state of the files). | 67 /// tests (since some tests modify the state of the files). |
| 64 testUriResolver = new InMemoryUriResolver(testFiles); | 68 testResourceProvider = createTestResourceProvider(testFiles); |
| 69 testUriResolver = new ResourceUriResolver(testResourceProvider); |
| 65 context = new TypeResolver.fromMock(mockSdkSources, options, | 70 context = new TypeResolver.fromMock(mockSdkSources, options, |
| 66 otherResolvers: [testUriResolver]).context; | 71 otherResolvers: [testUriResolver]).context; |
| 67 graph = new SourceGraph(context, new LogReporter(context), options); | 72 graph = new SourceGraph(context, new LogReporter(context), options); |
| 68 }); | 73 }); |
| 69 | 74 |
| 75 updateFile(Source source, [String newContents]) { |
| 76 var path = testResourceProvider.pathContext.fromUri(source.uri); |
| 77 if (newContents == null) newContents = source.contents.data; |
| 78 testResourceProvider.updateFile(path, newContents); |
| 79 } |
| 80 |
| 70 group('HTML deps', () { | 81 group('HTML deps', () { |
| 71 test('initial deps', () { | 82 test('initial deps', () { |
| 72 var i1 = nodeOf('/index1.html'); | 83 var i1 = nodeOf('/index1.html'); |
| 73 var i2 = nodeOf('/index2.html'); | 84 var i2 = nodeOf('/index2.html'); |
| 74 expect(i1.scripts.length, 0); | 85 expect(i1.scripts.length, 0); |
| 75 expect(i2.scripts.length, 0); | 86 expect(i2.scripts.length, 0); |
| 76 i1.update(); | 87 i1.update(); |
| 77 i2.update(); | 88 i2.update(); |
| 78 expect(i1.scripts.length, 0); | 89 expect(i1.scripts.length, 0); |
| 79 expect(i2.scripts.length, 1); | 90 expect(i2.scripts.length, 1); |
| 80 expect(i2.scripts.first, nodeOf('/a1.dart')); | 91 expect(i2.scripts.first, nodeOf('/a1.dart')); |
| 81 }); | 92 }); |
| 82 | 93 |
| 83 test('add a dep', () { | 94 test('add a dep', () { |
| 84 // After initial load, dependencies are 0: | 95 // After initial load, dependencies are 0: |
| 85 var node = nodeOf('/index1.html'); | 96 var node = nodeOf('/index1.html'); |
| 86 node.update(); | 97 node.update(); |
| 87 expect(node.scripts.length, 0); | 98 expect(node.scripts.length, 0); |
| 88 | 99 |
| 89 // Adding the dependency is discovered on the next round of updates: | 100 // Adding the dependency is discovered on the next round of updates: |
| 90 node.source.contents.modificationTime++; | 101 updateFile(node.source, |
| 91 node.source.contents.data = | 102 '<script type="application/dart" src="a2.dart"></script>'); |
| 92 '<script type="application/dart" src="a2.dart"></script>'; | |
| 93 expect(node.scripts.length, 0); | 103 expect(node.scripts.length, 0); |
| 94 node.update(); | 104 node.update(); |
| 95 expect(node.scripts.length, 1); | 105 expect(node.scripts.length, 1); |
| 96 expect(node.scripts.first, nodeOf('/a2.dart')); | 106 expect(node.scripts.first, nodeOf('/a2.dart')); |
| 97 }); | 107 }); |
| 98 | 108 |
| 99 test('add more deps', () { | 109 test('add more deps', () { |
| 100 // After initial load, dependencies are 1: | 110 // After initial load, dependencies are 1: |
| 101 var node = nodeOf('/index2.html'); | 111 var node = nodeOf('/index2.html'); |
| 102 node.update(); | 112 node.update(); |
| 103 expect(node.scripts.length, 1); | 113 expect(node.scripts.length, 1); |
| 104 expect(node.scripts.first, nodeOf('/a1.dart')); | 114 expect(node.scripts.first, nodeOf('/a1.dart')); |
| 105 | 115 |
| 106 node.source.contents.modificationTime++; | 116 updateFile(node.source, node.source.contents.data + |
| 107 node.source.contents.data += | 117 '<script type="application/dart" src="a2.dart"></script>'); |
| 108 '<script type="application/dart" src="a2.dart"></script>'; | |
| 109 expect(node.scripts.length, 1); | 118 expect(node.scripts.length, 1); |
| 110 node.update(); | 119 node.update(); |
| 111 expect(node.scripts.length, 2); | 120 expect(node.scripts.length, 2); |
| 112 expect(node.scripts.first, nodeOf('/a1.dart')); | 121 expect(node.scripts.first, nodeOf('/a1.dart')); |
| 113 expect(node.scripts.last, nodeOf('/a2.dart')); | 122 expect(node.scripts.last, nodeOf('/a2.dart')); |
| 114 }); | 123 }); |
| 115 | 124 |
| 116 test('remove all deps', () { | 125 test('remove all deps', () { |
| 117 // After initial load, dependencies are 1: | 126 // After initial load, dependencies are 1: |
| 118 var node = nodeOf('/index2.html'); | 127 var node = nodeOf('/index2.html'); |
| 119 node.update(); | 128 node.update(); |
| 120 expect(node.scripts.length, 1); | 129 expect(node.scripts.length, 1); |
| 121 expect(node.scripts.first, nodeOf('/a1.dart')); | 130 expect(node.scripts.first, nodeOf('/a1.dart')); |
| 122 | 131 |
| 123 // Removing the dependency is discovered on the next round of updates: | 132 // Removing the dependency is discovered on the next round of updates: |
| 124 node.source.contents.modificationTime++; | 133 updateFile(node.source, ''); |
| 125 node.source.contents.data = ''; | |
| 126 expect(node.scripts.length, 1); | 134 expect(node.scripts.length, 1); |
| 127 node.update(); | 135 node.update(); |
| 128 expect(node.scripts.length, 0); | 136 expect(node.scripts.length, 0); |
| 129 }); | 137 }); |
| 130 }); | 138 }); |
| 131 | 139 |
| 132 group('Dart deps', () { | 140 group('Dart deps', () { |
| 133 test('initial deps', () { | 141 test('initial deps', () { |
| 134 var a1 = nodeOf('/a1.dart'); | 142 var a1 = nodeOf('/a1.dart'); |
| 135 var a2 = nodeOf('/a2.dart'); | 143 var a2 = nodeOf('/a2.dart'); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 155 expect(a2.parts.contains(nodeOf('/a6.dart')), isTrue); | 163 expect(a2.parts.contains(nodeOf('/a6.dart')), isTrue); |
| 156 }); | 164 }); |
| 157 | 165 |
| 158 test('add deps', () { | 166 test('add deps', () { |
| 159 var node = nodeOf('/a1.dart'); | 167 var node = nodeOf('/a1.dart'); |
| 160 node.update(); | 168 node.update(); |
| 161 expect(node.imports.length, 0); | 169 expect(node.imports.length, 0); |
| 162 expect(node.exports.length, 0); | 170 expect(node.exports.length, 0); |
| 163 expect(node.parts.length, 0); | 171 expect(node.parts.length, 0); |
| 164 | 172 |
| 165 node.source.contents.modificationTime++; | 173 updateFile( |
| 166 node.source.contents.data = | 174 node.source, 'import "a3.dart"; export "a5.dart"; part "a8.dart";'); |
| 167 'import "a3.dart"; export "a5.dart"; part "a8.dart";'; | |
| 168 node.update(); | 175 node.update(); |
| 169 | 176 |
| 170 expect(node.imports.length, 1); | 177 expect(node.imports.length, 1); |
| 171 expect(node.exports.length, 1); | 178 expect(node.exports.length, 1); |
| 172 expect(node.parts.length, 1); | 179 expect(node.parts.length, 1); |
| 173 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 180 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 174 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); | 181 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); |
| 175 expect(node.parts.contains(nodeOf('/a8.dart')), isTrue); | 182 expect(node.parts.contains(nodeOf('/a8.dart')), isTrue); |
| 176 }); | 183 }); |
| 177 | 184 |
| 178 test('remove deps', () { | 185 test('remove deps', () { |
| 179 var node = nodeOf('/a2.dart'); | 186 var node = nodeOf('/a2.dart'); |
| 180 node.update(); | 187 node.update(); |
| 181 expect(node.imports.length, 2); | 188 expect(node.imports.length, 2); |
| 182 expect(node.exports.length, 1); | 189 expect(node.exports.length, 1); |
| 183 expect(node.parts.length, 1); | 190 expect(node.parts.length, 1); |
| 184 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 191 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 185 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); | 192 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); |
| 186 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); | 193 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); |
| 187 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); | 194 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); |
| 188 | 195 |
| 189 node.source.contents.modificationTime++; | 196 updateFile( |
| 190 node.source.contents.data = | 197 node.source, 'import "a3.dart"; export "a7.dart"; part "a8.dart";'); |
| 191 'import "a3.dart"; export "a7.dart"; part "a8.dart";'; | |
| 192 node.update(); | 198 node.update(); |
| 193 | 199 |
| 194 expect(node.imports.length, 1); | 200 expect(node.imports.length, 1); |
| 195 expect(node.exports.length, 1); | 201 expect(node.exports.length, 1); |
| 196 expect(node.parts.length, 1); | 202 expect(node.parts.length, 1); |
| 197 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 203 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 198 expect(node.exports.contains(nodeOf('/a7.dart')), isTrue); | 204 expect(node.exports.contains(nodeOf('/a7.dart')), isTrue); |
| 199 expect(node.parts.contains(nodeOf('/a8.dart')), isTrue); | 205 expect(node.parts.contains(nodeOf('/a8.dart')), isTrue); |
| 200 }); | 206 }); |
| 201 | 207 |
| 202 test('change part to library', () { | 208 test('change part to library', () { |
| 203 var node = nodeOf('/a2.dart'); | 209 var node = nodeOf('/a2.dart'); |
| 204 node.update(); | 210 node.update(); |
| 205 expect(node.imports.length, 2); | 211 expect(node.imports.length, 2); |
| 206 expect(node.exports.length, 1); | 212 expect(node.exports.length, 1); |
| 207 expect(node.parts.length, 1); | 213 expect(node.parts.length, 1); |
| 208 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 214 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 209 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); | 215 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); |
| 210 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); | 216 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); |
| 211 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); | 217 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); |
| 212 | 218 |
| 213 node.source.contents.modificationTime++; | 219 updateFile(node.source, ''' |
| 214 node.source.contents.data = ''' | |
| 215 library a2; | 220 library a2; |
| 216 import 'a3.dart'; | 221 import 'a3.dart'; |
| 217 import 'a4.dart'; | 222 import 'a4.dart'; |
| 218 export 'a5.dart'; | 223 export 'a5.dart'; |
| 219 import 'a6.dart'; // changed from part | 224 import 'a6.dart'; // changed from part |
| 220 '''; | 225 '''); |
| 221 var a6 = nodeOf('/a6.dart'); | 226 var a6 = nodeOf('/a6.dart'); |
| 222 a6.source.contents.modificationTime++; | 227 updateFile(a6.source, ''); |
| 223 a6.source.contents.data = ''; | |
| 224 node.update(); | 228 node.update(); |
| 225 | 229 |
| 226 expect(node.imports.length, 3); | 230 expect(node.imports.length, 3); |
| 227 expect(node.exports.length, 1); | 231 expect(node.exports.length, 1); |
| 228 expect(node.parts.length, 0); | 232 expect(node.parts.length, 0); |
| 229 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 233 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 230 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); | 234 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); |
| 231 expect(node.imports.contains(nodeOf('/a6.dart')), isTrue); | 235 expect(node.imports.contains(nodeOf('/a6.dart')), isTrue); |
| 232 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); | 236 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); |
| 233 | 237 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 246 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 250 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 247 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); | 251 expect(node.imports.contains(nodeOf('/a4.dart')), isTrue); |
| 248 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); | 252 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); |
| 249 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); | 253 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); |
| 250 | 254 |
| 251 a4.update(); | 255 a4.update(); |
| 252 expect(a4.imports.length, 0); | 256 expect(a4.imports.length, 0); |
| 253 expect(a4.exports.length, 1); | 257 expect(a4.exports.length, 1); |
| 254 expect(a4.parts.length, 0); | 258 expect(a4.parts.length, 0); |
| 255 | 259 |
| 256 node.source.contents.modificationTime++; | 260 updateFile(node.source, ''' |
| 257 node.source.contents.data = ''' | |
| 258 library a2; | 261 library a2; |
| 259 import 'a3.dart'; | 262 import 'a3.dart'; |
| 260 part 'a4.dart'; // changed from export | 263 part 'a4.dart'; // changed from export |
| 261 export 'a5.dart'; | 264 export 'a5.dart'; |
| 262 part 'a6.dart'; | 265 part 'a6.dart'; |
| 263 '''; | 266 '''); |
| 264 node.update(); | 267 node.update(); |
| 265 | 268 |
| 266 expect(node.imports.length, 1); | 269 expect(node.imports.length, 1); |
| 267 expect(node.exports.length, 1); | 270 expect(node.exports.length, 1); |
| 268 expect(node.parts.length, 2); | 271 expect(node.parts.length, 2); |
| 269 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); | 272 expect(node.imports.contains(nodeOf('/a3.dart')), isTrue); |
| 270 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); | 273 expect(node.exports.contains(nodeOf('/a5.dart')), isTrue); |
| 271 expect(node.parts.contains(nodeOf('/a4.dart')), isTrue); | 274 expect(node.parts.contains(nodeOf('/a4.dart')), isTrue); |
| 272 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); | 275 expect(node.parts.contains(nodeOf('/a6.dart')), isTrue); |
| 273 | 276 |
| 274 // Note, technically we never modified the contents of a4 and it contains | 277 // Note, technically we never modified the contents of a4 and it contains |
| 275 // an export. This is invalid Dart, but we'll let the analyzer report that | 278 // an export. This is invalid Dart, but we'll let the analyzer report that |
| 276 // error instead of doing so ourselves. | 279 // error instead of doing so ourselves. |
| 277 expect(a4.imports.length, 0); | 280 expect(a4.imports.length, 0); |
| 278 expect(a4.exports.length, 1); | 281 expect(a4.exports.length, 1); |
| 279 expect(a4.parts.length, 0); | 282 expect(a4.parts.length, 0); |
| 280 | 283 |
| 281 // And change it back. | 284 // And change it back. |
| 282 node.source.contents.modificationTime++; | 285 updateFile(node.source, ''' |
| 283 node.source.contents.data = ''' | |
| 284 library a2; | 286 library a2; |
| 285 import 'a3.dart'; | 287 import 'a3.dart'; |
| 286 import 'a4.dart'; // changed again | 288 import 'a4.dart'; // changed again |
| 287 export 'a5.dart'; | 289 export 'a5.dart'; |
| 288 part 'a6.dart'; | 290 part 'a6.dart'; |
| 289 '''; | 291 '''); |
| 290 node.update(); | 292 node.update(); |
| 291 expect(node.imports.contains(a4), isTrue); | 293 expect(node.imports.contains(a4), isTrue); |
| 292 expect(a4.imports.length, 0); | 294 expect(a4.imports.length, 0); |
| 293 expect(a4.exports.length, 1); | 295 expect(a4.exports.length, 1); |
| 294 expect(a4.parts.length, 0); | 296 expect(a4.parts.length, 0); |
| 295 }); | 297 }); |
| 296 }); | 298 }); |
| 297 | 299 |
| 298 group('local changes', () { | 300 group('local changes', () { |
| 299 group('needs rebuild', () { | 301 group('needs rebuild', () { |
| 300 test('in HTML', () { | 302 test('in HTML', () { |
| 301 var node = nodeOf('/index1.html'); | 303 var node = nodeOf('/index1.html'); |
| 302 node.update(); | 304 node.update(); |
| 303 expect(node.needsRebuild, isTrue); | 305 expect(node.needsRebuild, isTrue); |
| 304 node.needsRebuild = false; | 306 node.needsRebuild = false; |
| 305 | 307 |
| 306 node.update(); | 308 node.update(); |
| 307 expect(node.needsRebuild, isFalse); | 309 expect(node.needsRebuild, isFalse); |
| 308 | 310 |
| 309 // For now, an empty modification is enough to trigger a rebuild | 311 // For now, an empty modification is enough to trigger a rebuild |
| 310 node.source.contents.modificationTime++; | 312 updateFile(node.source); |
| 311 expect(node.needsRebuild, isFalse); | 313 expect(node.needsRebuild, isFalse); |
| 312 node.update(); | 314 node.update(); |
| 313 expect(node.needsRebuild, isTrue); | 315 expect(node.needsRebuild, isTrue); |
| 314 }); | 316 }); |
| 315 | 317 |
| 316 test('main library in Dart', () { | 318 test('main library in Dart', () { |
| 317 var node = nodeOf('/a2.dart'); | 319 var node = nodeOf('/a2.dart'); |
| 318 var partNode = nodeOf('/a6.dart'); | 320 var partNode = nodeOf('/a6.dart'); |
| 319 node.update(); | 321 node.update(); |
| 320 expect(node.needsRebuild, isTrue); | 322 expect(node.needsRebuild, isTrue); |
| 321 node.needsRebuild = false; | 323 node.needsRebuild = false; |
| 322 partNode.needsRebuild = false; | 324 partNode.needsRebuild = false; |
| 323 | 325 |
| 324 node.update(); | 326 node.update(); |
| 325 expect(node.needsRebuild, isFalse); | 327 expect(node.needsRebuild, isFalse); |
| 326 | 328 |
| 327 // For now, an empty modification is enough to trigger a rebuild | 329 // For now, an empty modification is enough to trigger a rebuild |
| 328 node.source.contents.modificationTime++; | 330 updateFile(node.source); |
| 329 expect(node.needsRebuild, isFalse); | 331 expect(node.needsRebuild, isFalse); |
| 330 node.update(); | 332 node.update(); |
| 331 expect(node.needsRebuild, isTrue); | 333 expect(node.needsRebuild, isTrue); |
| 332 }); | 334 }); |
| 333 | 335 |
| 334 test('part of library in Dart', () { | 336 test('part of library in Dart', () { |
| 335 var node = nodeOf('/a2.dart'); | 337 var node = nodeOf('/a2.dart'); |
| 336 var importNode = nodeOf('/a3.dart'); | 338 var importNode = nodeOf('/a3.dart'); |
| 337 var exportNode = nodeOf('/a5.dart'); | 339 var exportNode = nodeOf('/a5.dart'); |
| 338 var partNode = nodeOf('/a6.dart'); | 340 var partNode = nodeOf('/a6.dart'); |
| 339 node.update(); | 341 node.update(); |
| 340 expect(node.needsRebuild, isTrue); | 342 expect(node.needsRebuild, isTrue); |
| 341 node.needsRebuild = false; | 343 node.needsRebuild = false; |
| 342 partNode.needsRebuild = false; | 344 partNode.needsRebuild = false; |
| 343 | 345 |
| 344 node.update(); | 346 node.update(); |
| 345 expect(node.needsRebuild, isFalse); | 347 expect(node.needsRebuild, isFalse); |
| 346 | 348 |
| 347 // Modification in imported/exported node makes no difference for local | 349 // Modification in imported/exported node makes no difference for local |
| 348 // rebuild label (globally that's tested elsewhere) | 350 // rebuild label (globally that's tested elsewhere) |
| 349 importNode.source.contents.modificationTime++; | 351 updateFile(importNode.source); |
| 350 exportNode.source.contents.modificationTime++; | 352 updateFile(exportNode.source); |
| 351 node.update(); | 353 node.update(); |
| 352 expect(node.needsRebuild, isFalse); | 354 expect(node.needsRebuild, isFalse); |
| 353 expect(partNode.needsRebuild, isFalse); | 355 expect(partNode.needsRebuild, isFalse); |
| 354 | 356 |
| 355 // Modification in part triggers change in containing library: | 357 // Modification in part triggers change in containing library: |
| 356 partNode.source.contents.modificationTime++; | 358 updateFile(partNode.source); |
| 357 expect(node.needsRebuild, isFalse); | 359 expect(node.needsRebuild, isFalse); |
| 358 expect(partNode.needsRebuild, isFalse); | 360 expect(partNode.needsRebuild, isFalse); |
| 359 node.update(); | 361 node.update(); |
| 360 expect(node.needsRebuild, isTrue); | 362 expect(node.needsRebuild, isTrue); |
| 361 expect(partNode.needsRebuild, isTrue); | 363 expect(partNode.needsRebuild, isTrue); |
| 362 }); | 364 }); |
| 363 }); | 365 }); |
| 364 | 366 |
| 365 group('structure change', () { | 367 group('structure change', () { |
| 366 test('no mod in HTML', () { | 368 test('no mod in HTML', () { |
| 367 var node = nodeOf('/index2.html'); | 369 var node = nodeOf('/index2.html'); |
| 368 node.update(); | 370 node.update(); |
| 369 expect(node.structureChanged, isTrue); | 371 expect(node.structureChanged, isTrue); |
| 370 node.structureChanged = false; | 372 node.structureChanged = false; |
| 371 | 373 |
| 372 node.update(); | 374 node.update(); |
| 373 expect(node.structureChanged, isFalse); | 375 expect(node.structureChanged, isFalse); |
| 374 | 376 |
| 375 // An empty modification will not trigger a structural change | 377 // An empty modification will not trigger a structural change |
| 376 node.source.contents.modificationTime++; | 378 updateFile(node.source); |
| 377 expect(node.structureChanged, isFalse); | 379 expect(node.structureChanged, isFalse); |
| 378 node.update(); | 380 node.update(); |
| 379 expect(node.structureChanged, isFalse); | 381 expect(node.structureChanged, isFalse); |
| 380 }); | 382 }); |
| 381 | 383 |
| 382 test('added scripts in HTML', () { | 384 test('added scripts in HTML', () { |
| 383 var node = nodeOf('/index2.html'); | 385 var node = nodeOf('/index2.html'); |
| 384 node.update(); | 386 node.update(); |
| 385 expect(node.structureChanged, isTrue); | 387 expect(node.structureChanged, isTrue); |
| 386 expect(node.scripts.length, 1); | 388 expect(node.scripts.length, 1); |
| 387 | 389 |
| 388 node.structureChanged = false; | 390 node.structureChanged = false; |
| 389 node.update(); | 391 node.update(); |
| 390 expect(node.structureChanged, isFalse); | 392 expect(node.structureChanged, isFalse); |
| 391 | 393 |
| 392 // This change will not include new script tags: | 394 // This change will not include new script tags: |
| 393 node.source.contents.modificationTime++; | 395 updateFile(node.source, node.source.contents.data + '<div></div>'); |
| 394 node.source.contents.data += '<div></div>'; | |
| 395 expect(node.structureChanged, isFalse); | 396 expect(node.structureChanged, isFalse); |
| 396 node.update(); | 397 node.update(); |
| 397 expect(node.structureChanged, isFalse); | 398 expect(node.structureChanged, isFalse); |
| 398 expect(node.scripts.length, 1); | 399 expect(node.scripts.length, 1); |
| 399 | 400 |
| 400 node.source.contents.modificationTime++; | 401 updateFile(node.source, node.source.contents.data + |
| 401 node.source.contents.data += | 402 '<script type="application/dart" src="a4.dart"></script>'); |
| 402 '<script type="application/dart" src="a4.dart"></script>'; | |
| 403 expect(node.structureChanged, isFalse); | 403 expect(node.structureChanged, isFalse); |
| 404 node.update(); | 404 node.update(); |
| 405 expect(node.structureChanged, isTrue); | 405 expect(node.structureChanged, isTrue); |
| 406 expect(node.scripts.length, 2); | 406 expect(node.scripts.length, 2); |
| 407 }); | 407 }); |
| 408 | 408 |
| 409 test('no mod in Dart', () { | 409 test('no mod in Dart', () { |
| 410 var node = nodeOf('/a2.dart'); | 410 var node = nodeOf('/a2.dart'); |
| 411 var importNode = nodeOf('/a3.dart'); | 411 var importNode = nodeOf('/a3.dart'); |
| 412 var exportNode = nodeOf('/a5.dart'); | 412 var exportNode = nodeOf('/a5.dart'); |
| 413 var partNode = nodeOf('/a6.dart'); | 413 var partNode = nodeOf('/a6.dart'); |
| 414 node.update(); | 414 node.update(); |
| 415 expect(node.structureChanged, isTrue); | 415 expect(node.structureChanged, isTrue); |
| 416 node.structureChanged = false; | 416 node.structureChanged = false; |
| 417 | 417 |
| 418 node.update(); | 418 node.update(); |
| 419 expect(node.structureChanged, isFalse); | 419 expect(node.structureChanged, isFalse); |
| 420 | 420 |
| 421 // These modifications make no difference at all. | 421 // These modifications make no difference at all. |
| 422 importNode.source.contents.modificationTime++; | 422 updateFile(importNode.source); |
| 423 exportNode.source.contents.modificationTime++; | 423 updateFile(exportNode.source); |
| 424 partNode.source.contents.modificationTime++; | 424 updateFile(partNode.source); |
| 425 node.source.contents.modificationTime++; | 425 updateFile(node.source); |
| 426 | 426 |
| 427 expect(node.structureChanged, isFalse); | 427 expect(node.structureChanged, isFalse); |
| 428 node.update(); | 428 node.update(); |
| 429 expect(node.structureChanged, isFalse); | 429 expect(node.structureChanged, isFalse); |
| 430 }); | 430 }); |
| 431 | 431 |
| 432 test('same directives, different order', () { | 432 test('same directives, different order', () { |
| 433 var node = nodeOf('/a2.dart'); | 433 var node = nodeOf('/a2.dart'); |
| 434 node.update(); | 434 node.update(); |
| 435 expect(node.structureChanged, isTrue); | 435 expect(node.structureChanged, isTrue); |
| 436 node.structureChanged = false; | 436 node.structureChanged = false; |
| 437 | 437 |
| 438 node.update(); | 438 node.update(); |
| 439 expect(node.structureChanged, isFalse); | 439 expect(node.structureChanged, isFalse); |
| 440 | 440 |
| 441 // modified order of imports, but structure stays the same: | 441 // modified order of imports, but structure stays the same: |
| 442 node.source.contents.modificationTime++; | 442 updateFile(node.source, 'import "a4.dart"; import "a3.dart"; ' |
| 443 node.source.contents.data = 'import "a4.dart"; import "a3.dart"; ' | 443 'export "a5.dart"; part "a6.dart";'); |
| 444 'export "a5.dart"; part "a6.dart";'; | |
| 445 node.update(); | 444 node.update(); |
| 446 | 445 |
| 447 expect(node.structureChanged, isFalse); | 446 expect(node.structureChanged, isFalse); |
| 448 node.update(); | 447 node.update(); |
| 449 expect(node.structureChanged, isFalse); | 448 expect(node.structureChanged, isFalse); |
| 450 }); | 449 }); |
| 451 | 450 |
| 452 test('changed parts', () { | 451 test('changed parts', () { |
| 453 var node = nodeOf('/a2.dart'); | 452 var node = nodeOf('/a2.dart'); |
| 454 node.update(); | 453 node.update(); |
| 455 expect(node.structureChanged, isTrue); | 454 expect(node.structureChanged, isTrue); |
| 456 node.structureChanged = false; | 455 node.structureChanged = false; |
| 457 | 456 |
| 458 node.update(); | 457 node.update(); |
| 459 expect(node.structureChanged, isFalse); | 458 expect(node.structureChanged, isFalse); |
| 460 | 459 |
| 461 // added one. | 460 // added one. |
| 462 node.source.contents.modificationTime++; | 461 updateFile(node.source, 'import "a4.dart"; import "a3.dart"; ' |
| 463 node.source.contents.data = 'import "a4.dart"; import "a3.dart"; ' | 462 'export "a5.dart"; part "a6.dart"; part "a7.dart";'); |
| 464 'export "a5.dart"; part "a6.dart"; part "a7.dart";'; | |
| 465 expect(node.structureChanged, isFalse); | 463 expect(node.structureChanged, isFalse); |
| 466 node.update(); | 464 node.update(); |
| 467 expect(node.structureChanged, isTrue); | 465 expect(node.structureChanged, isTrue); |
| 468 | 466 |
| 469 // no change | 467 // no change |
| 470 node.structureChanged = false; | 468 node.structureChanged = false; |
| 471 node.source.contents.modificationTime++; | 469 updateFile(node.source); |
| 472 node.update(); | 470 node.update(); |
| 473 expect(node.structureChanged, isFalse); | 471 expect(node.structureChanged, isFalse); |
| 474 | 472 |
| 475 // removed one | 473 // removed one |
| 476 node.source.contents.modificationTime++; | 474 updateFile(node.source); |
| 477 node.source.contents.data = 'import "a4.dart"; import "a3.dart"; ' | 475 updateFile(node.source, 'import "a4.dart"; import "a3.dart"; ' |
| 478 'export "a5.dart"; part "a7.dart";'; | 476 'export "a5.dart"; part "a7.dart";'); |
| 479 expect(node.structureChanged, isFalse); | 477 expect(node.structureChanged, isFalse); |
| 480 node.update(); | 478 node.update(); |
| 481 expect(node.structureChanged, isTrue); | 479 expect(node.structureChanged, isTrue); |
| 482 }); | 480 }); |
| 483 | 481 |
| 484 test('changed import', () { | 482 test('changed import', () { |
| 485 var node = nodeOf('/a2.dart'); | 483 var node = nodeOf('/a2.dart'); |
| 486 node.update(); | 484 node.update(); |
| 487 expect(node.structureChanged, isTrue); | 485 expect(node.structureChanged, isTrue); |
| 488 node.structureChanged = false; | 486 node.structureChanged = false; |
| 489 | 487 |
| 490 node.update(); | 488 node.update(); |
| 491 expect(node.structureChanged, isFalse); | 489 expect(node.structureChanged, isFalse); |
| 492 | 490 |
| 493 // added one. | 491 // added one. |
| 494 node.source.contents.modificationTime++; | 492 updateFile(node.source, |
| 495 node.source.contents.data = | |
| 496 'import "a4.dart"; import "a3.dart"; import "a7.dart";' | 493 'import "a4.dart"; import "a3.dart"; import "a7.dart";' |
| 497 'export "a5.dart"; part "a6.dart";'; | 494 'export "a5.dart"; part "a6.dart";'); |
| 498 expect(node.structureChanged, isFalse); | 495 expect(node.structureChanged, isFalse); |
| 499 node.update(); | 496 node.update(); |
| 500 expect(node.structureChanged, isTrue); | 497 expect(node.structureChanged, isTrue); |
| 501 | 498 |
| 502 // no change | 499 // no change |
| 503 node.structureChanged = false; | 500 node.structureChanged = false; |
| 504 node.source.contents.modificationTime++; | 501 updateFile(node.source); |
| 505 node.update(); | 502 node.update(); |
| 506 expect(node.structureChanged, isFalse); | 503 expect(node.structureChanged, isFalse); |
| 507 | 504 |
| 508 // removed one | 505 // removed one |
| 509 node.source.contents.modificationTime++; | 506 updateFile(node.source, 'import "a4.dart"; import "a7.dart"; ' |
| 510 node.source.contents.data = 'import "a4.dart"; import "a7.dart"; ' | 507 'export "a5.dart"; part "a6.dart";'); |
| 511 'export "a5.dart"; part "a6.dart";'; | |
| 512 expect(node.structureChanged, isFalse); | 508 expect(node.structureChanged, isFalse); |
| 513 node.update(); | 509 node.update(); |
| 514 expect(node.structureChanged, isTrue); | 510 expect(node.structureChanged, isTrue); |
| 515 }); | 511 }); |
| 516 | 512 |
| 517 test('changed exports', () { | 513 test('changed exports', () { |
| 518 var node = nodeOf('/a2.dart'); | 514 var node = nodeOf('/a2.dart'); |
| 519 node.update(); | 515 node.update(); |
| 520 expect(node.structureChanged, isTrue); | 516 expect(node.structureChanged, isTrue); |
| 521 node.structureChanged = false; | 517 node.structureChanged = false; |
| 522 | 518 |
| 523 node.update(); | 519 node.update(); |
| 524 expect(node.structureChanged, isFalse); | 520 expect(node.structureChanged, isFalse); |
| 525 | 521 |
| 526 // added one. | 522 // added one. |
| 527 node.source.contents.modificationTime++; | 523 updateFile(node.source, 'import "a4.dart"; import "a3.dart";' |
| 528 node.source.contents.data = 'import "a4.dart"; import "a3.dart";' | 524 'export "a5.dart"; export "a9.dart"; part "a6.dart";'); |
| 529 'export "a5.dart"; export "a9.dart"; part "a6.dart";'; | |
| 530 expect(node.structureChanged, isFalse); | 525 expect(node.structureChanged, isFalse); |
| 531 node.update(); | 526 node.update(); |
| 532 expect(node.structureChanged, isTrue); | 527 expect(node.structureChanged, isTrue); |
| 533 | 528 |
| 534 // no change | 529 // no change |
| 535 node.structureChanged = false; | 530 node.structureChanged = false; |
| 536 node.source.contents.modificationTime++; | 531 updateFile(node.source); |
| 537 node.update(); | 532 node.update(); |
| 538 expect(node.structureChanged, isFalse); | 533 expect(node.structureChanged, isFalse); |
| 539 | 534 |
| 540 // removed one | 535 // removed one |
| 541 node.source.contents.modificationTime++; | 536 updateFile(node.source, 'import "a4.dart"; import "a3.dart"; ' |
| 542 node.source.contents.data = 'import "a4.dart"; import "a3.dart"; ' | 537 'export "a5.dart"; part "a6.dart";'); |
| 543 'export "a5.dart"; part "a6.dart";'; | |
| 544 expect(node.structureChanged, isFalse); | 538 expect(node.structureChanged, isFalse); |
| 545 node.update(); | 539 node.update(); |
| 546 expect(node.structureChanged, isTrue); | 540 expect(node.structureChanged, isTrue); |
| 547 }); | 541 }); |
| 548 }); | 542 }); |
| 549 }); | 543 }); |
| 550 | 544 |
| 551 group('refresh structure and marks', () { | 545 group('refresh structure and marks', () { |
| 552 test('initial marks', () { | 546 test('initial marks', () { |
| 553 var node = nodeOf('/index3.html'); | 547 var node = nodeOf('/index3.html'); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 | |-- a6.dart (part) | 598 | |-- a6.dart (part) |
| 605 $_RUNTIME_GRAPH | 599 $_RUNTIME_GRAPH |
| 606 '''); | 600 '''); |
| 607 }); | 601 }); |
| 608 | 602 |
| 609 test('needsRebuild mark updated on local modifications', () { | 603 test('needsRebuild mark updated on local modifications', () { |
| 610 var node = nodeOf('/index3.html'); | 604 var node = nodeOf('/index3.html'); |
| 611 refreshStructureAndMarks(node); | 605 refreshStructureAndMarks(node); |
| 612 clearMarks(node); | 606 clearMarks(node); |
| 613 var a3 = nodeOf('/a3.dart'); | 607 var a3 = nodeOf('/a3.dart'); |
| 614 a3.source.contents.modificationTime++; | 608 updateFile(a3.source); |
| 615 | 609 |
| 616 refreshStructureAndMarks(node); | 610 refreshStructureAndMarks(node); |
| 617 expectGraph(node, ''' | 611 expectGraph(node, ''' |
| 618 index3.html | 612 index3.html |
| 619 |-- a2.dart | 613 |-- a2.dart |
| 620 | |-- a3.dart [needs-rebuild] | 614 | |-- a3.dart [needs-rebuild] |
| 621 | |-- a4.dart | 615 | |-- a4.dart |
| 622 | | |-- a10.dart | 616 | | |-- a10.dart |
| 623 | |-- a5.dart | 617 | |-- a5.dart |
| 624 | |-- a6.dart (part) | 618 | |-- a6.dart (part) |
| 625 $_RUNTIME_GRAPH | 619 $_RUNTIME_GRAPH |
| 626 '''); | 620 '''); |
| 627 }); | 621 }); |
| 628 | 622 |
| 629 test('structuredChanged mark updated on structure modifications', () { | 623 test('structuredChanged mark updated on structure modifications', () { |
| 630 var node = nodeOf('/index3.html'); | 624 var node = nodeOf('/index3.html'); |
| 631 refreshStructureAndMarks(node); | 625 refreshStructureAndMarks(node); |
| 632 clearMarks(node); | 626 clearMarks(node); |
| 633 var a5 = nodeOf('/a5.dart'); | 627 var a5 = nodeOf('/a5.dart'); |
| 634 a5.source.contents.modificationTime++; | 628 updateFile(a5.source, 'import "a8.dart";'); |
| 635 a5.source.contents.data = 'import "a8.dart";'; | |
| 636 | 629 |
| 637 refreshStructureAndMarks(node); | 630 refreshStructureAndMarks(node); |
| 638 expectGraph(node, ''' | 631 expectGraph(node, ''' |
| 639 index3.html | 632 index3.html |
| 640 |-- a2.dart | 633 |-- a2.dart |
| 641 | |-- a3.dart | 634 | |-- a3.dart |
| 642 | |-- a4.dart | 635 | |-- a4.dart |
| 643 | | |-- a10.dart | 636 | | |-- a10.dart |
| 644 | |-- a5.dart [needs-rebuild] [structure-changed] | 637 | |-- a5.dart [needs-rebuild] [structure-changed] |
| 645 | | |-- a8.dart [needs-rebuild] [structure-changed] | 638 | | |-- a8.dart [needs-rebuild] [structure-changed] |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 rebuild(node, buildNoTransitiveChange); | 723 rebuild(node, buildNoTransitiveChange); |
| 731 expect(results, []); | 724 expect(results, []); |
| 732 }); | 725 }); |
| 733 | 726 |
| 734 test('modified part triggers building library', () { | 727 test('modified part triggers building library', () { |
| 735 var node = nodeOf('/index3.html'); | 728 var node = nodeOf('/index3.html'); |
| 736 rebuild(node, buildNoTransitiveChange); | 729 rebuild(node, buildNoTransitiveChange); |
| 737 results = []; | 730 results = []; |
| 738 | 731 |
| 739 var a6 = nodeOf('/a6.dart'); | 732 var a6 = nodeOf('/a6.dart'); |
| 740 a6.source.contents.modificationTime++; | 733 updateFile(a6.source); |
| 741 rebuild(node, buildNoTransitiveChange); | 734 rebuild(node, buildNoTransitiveChange); |
| 742 expect(results, ['a2.dart']); | 735 expect(results, ['a2.dart']); |
| 743 | 736 |
| 744 results = []; | 737 results = []; |
| 745 rebuild(node, buildNoTransitiveChange); | 738 rebuild(node, buildNoTransitiveChange); |
| 746 expect(results, []); | 739 expect(results, []); |
| 747 }); | 740 }); |
| 748 | 741 |
| 749 test('non-API change triggers build stays local', () { | 742 test('non-API change triggers build stays local', () { |
| 750 var node = nodeOf('/index3.html'); | 743 var node = nodeOf('/index3.html'); |
| 751 rebuild(node, buildNoTransitiveChange); | 744 rebuild(node, buildNoTransitiveChange); |
| 752 results = []; | 745 results = []; |
| 753 | 746 |
| 754 var a3 = nodeOf('/a3.dart'); | 747 var a3 = nodeOf('/a3.dart'); |
| 755 a3.source.contents.modificationTime++; | 748 updateFile(a3.source); |
| 756 rebuild(node, buildNoTransitiveChange); | 749 rebuild(node, buildNoTransitiveChange); |
| 757 expect(results, ['a3.dart']); | 750 expect(results, ['a3.dart']); |
| 758 | 751 |
| 759 results = []; | 752 results = []; |
| 760 rebuild(node, buildNoTransitiveChange); | 753 rebuild(node, buildNoTransitiveChange); |
| 761 expect(results, []); | 754 expect(results, []); |
| 762 }); | 755 }); |
| 763 | 756 |
| 764 test('no-API change in exported file stays local', () { | 757 test('no-API change in exported file stays local', () { |
| 765 var node = nodeOf('/index3.html'); | 758 var node = nodeOf('/index3.html'); |
| 766 rebuild(node, buildNoTransitiveChange); | 759 rebuild(node, buildNoTransitiveChange); |
| 767 results = []; | 760 results = []; |
| 768 | 761 |
| 769 // similar to the test above, but a10 is exported from a4. | 762 // similar to the test above, but a10 is exported from a4. |
| 770 var a3 = nodeOf('/a10.dart'); | 763 var a3 = nodeOf('/a10.dart'); |
| 771 a3.source.contents.modificationTime++; | 764 updateFile(a3.source); |
| 772 rebuild(node, buildNoTransitiveChange); | 765 rebuild(node, buildNoTransitiveChange); |
| 773 expect(results, ['a10.dart']); | 766 expect(results, ['a10.dart']); |
| 774 | 767 |
| 775 results = []; | 768 results = []; |
| 776 rebuild(node, buildNoTransitiveChange); | 769 rebuild(node, buildNoTransitiveChange); |
| 777 expect(results, []); | 770 expect(results, []); |
| 778 }); | 771 }); |
| 779 | 772 |
| 780 test('API change in lib, triggers build on imports', () { | 773 test('API change in lib, triggers build on imports', () { |
| 781 var node = nodeOf('/index3.html'); | 774 var node = nodeOf('/index3.html'); |
| 782 rebuild(node, buildNoTransitiveChange); | 775 rebuild(node, buildNoTransitiveChange); |
| 783 results = []; | 776 results = []; |
| 784 | 777 |
| 785 var a3 = nodeOf('/a3.dart'); | 778 var a3 = nodeOf('/a3.dart'); |
| 786 a3.source.contents.modificationTime++; | 779 updateFile(a3.source); |
| 787 rebuild(node, buildWithTransitiveChange); | 780 rebuild(node, buildWithTransitiveChange); |
| 788 expect(results, ['a3.dart', 'a2.dart']); | 781 expect(results, ['a3.dart', 'a2.dart']); |
| 789 | 782 |
| 790 results = []; | 783 results = []; |
| 791 rebuild(node, buildNoTransitiveChange); | 784 rebuild(node, buildNoTransitiveChange); |
| 792 expect(results, []); | 785 expect(results, []); |
| 793 }); | 786 }); |
| 794 | 787 |
| 795 test('API change in export, triggers build on imports', () { | 788 test('API change in export, triggers build on imports', () { |
| 796 var node = nodeOf('/index3.html'); | 789 var node = nodeOf('/index3.html'); |
| 797 rebuild(node, buildNoTransitiveChange); | 790 rebuild(node, buildNoTransitiveChange); |
| 798 results = []; | 791 results = []; |
| 799 | 792 |
| 800 var a3 = nodeOf('/a10.dart'); | 793 var a3 = nodeOf('/a10.dart'); |
| 801 a3.source.contents.modificationTime++; | 794 updateFile(a3.source); |
| 802 rebuild(node, buildWithTransitiveChange); | 795 rebuild(node, buildWithTransitiveChange); |
| 803 | 796 |
| 804 // Node: a4.dart reexports a10.dart, but it doesn't import it, so we don't | 797 // Node: a4.dart reexports a10.dart, but it doesn't import it, so we don't |
| 805 // need to rebuild it. | 798 // need to rebuild it. |
| 806 expect(results, ['a10.dart', 'a2.dart']); | 799 expect(results, ['a10.dart', 'a2.dart']); |
| 807 | 800 |
| 808 results = []; | 801 results = []; |
| 809 rebuild(node, buildNoTransitiveChange); | 802 rebuild(node, buildNoTransitiveChange); |
| 810 expect(results, []); | 803 expect(results, []); |
| 811 }); | 804 }); |
| 812 | 805 |
| 813 test('structural change rebuilds HTML, but skips unreachable code', () { | 806 test('structural change rebuilds HTML, but skips unreachable code', () { |
| 814 var node = nodeOf('/index3.html'); | 807 var node = nodeOf('/index3.html'); |
| 815 rebuild(node, buildNoTransitiveChange); | 808 rebuild(node, buildNoTransitiveChange); |
| 816 results = []; | 809 results = []; |
| 817 | 810 |
| 818 var a2 = nodeOf('/a2.dart'); | 811 var a2 = nodeOf('/a2.dart'); |
| 819 a2.source.contents.modificationTime++; | 812 updateFile(a2.source, 'import "a4.dart";'); |
| 820 a2.source.contents.data = 'import "a4.dart";'; | |
| 821 | 813 |
| 822 var a3 = nodeOf('/a3.dart'); | 814 var a3 = nodeOf('/a3.dart'); |
| 823 a3.source.contents.modificationTime++; | 815 updateFile(a3.source); |
| 824 rebuild(node, buildNoTransitiveChange); | 816 rebuild(node, buildNoTransitiveChange); |
| 825 | 817 |
| 826 // a3 will become unreachable, index3 reflects structural changes. | 818 // a3 will become unreachable, index3 reflects structural changes. |
| 827 expect(results, ['a2.dart', 'index3.html']); | 819 expect(results, ['a2.dart', 'index3.html']); |
| 828 | 820 |
| 829 results = []; | 821 results = []; |
| 830 rebuild(node, buildNoTransitiveChange); | 822 rebuild(node, buildNoTransitiveChange); |
| 831 expect(results, []); | 823 expect(results, []); |
| 832 }); | 824 }); |
| 833 | 825 |
| 834 test('newly discovered files get built too', () { | 826 test('newly discovered files get built too', () { |
| 835 var node = nodeOf('/index3.html'); | 827 var node = nodeOf('/index3.html'); |
| 836 rebuild(node, buildNoTransitiveChange); | 828 rebuild(node, buildNoTransitiveChange); |
| 837 results = []; | 829 results = []; |
| 838 | 830 |
| 839 var a2 = nodeOf('/a2.dart'); | 831 var a2 = nodeOf('/a2.dart'); |
| 840 a2.source.contents.modificationTime++; | 832 updateFile(a2.source, 'import "a9.dart";'); |
| 841 a2.source.contents.data = 'import "a9.dart";'; | |
| 842 | 833 |
| 843 rebuild(node, buildNoTransitiveChange); | 834 rebuild(node, buildNoTransitiveChange); |
| 844 expect(results, ['a8.dart', 'a9.dart', 'a2.dart', 'index3.html']); | 835 expect(results, ['a8.dart', 'a9.dart', 'a2.dart', 'index3.html']); |
| 845 | 836 |
| 846 results = []; | 837 results = []; |
| 847 rebuild(node, buildNoTransitiveChange); | 838 rebuild(node, buildNoTransitiveChange); |
| 848 expect(results, []); | 839 expect(results, []); |
| 849 }); | 840 }); |
| 850 | 841 |
| 851 group('file upgrades', () { | 842 group('file upgrades', () { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 866 |-- a2.dart | 857 |-- a2.dart |
| 867 | |-- a3.dart | 858 | |-- a3.dart |
| 868 | |-- a4.dart | 859 | |-- a4.dart |
| 869 | | |-- a10.dart | 860 | | |-- a10.dart |
| 870 | |-- a5.dart | 861 | |-- a5.dart |
| 871 | |-- a6.dart (part) | 862 | |-- a6.dart (part) |
| 872 $_RUNTIME_GRAPH | 863 $_RUNTIME_GRAPH |
| 873 '''); | 864 '''); |
| 874 | 865 |
| 875 // Modify the file first: | 866 // Modify the file first: |
| 876 a6.source.contents.modificationTime++; | 867 updateFile(a6.source, 'library a6; import "a5.dart";'); |
| 877 a6.source.contents.data = 'library a6; import "a5.dart";'; | |
| 878 results = []; | 868 results = []; |
| 879 rebuild(node, buildNoTransitiveChange); | 869 rebuild(node, buildNoTransitiveChange); |
| 880 | 870 |
| 881 // Looks to us like a change in a part, we'll report errors that the | 871 // Looks to us like a change in a part, we'll report errors that the |
| 882 // part is not really a part-file. Note that a6.dart is not included | 872 // part is not really a part-file. Note that a6.dart is not included |
| 883 // below, because we don't build it as a library. | 873 // below, because we don't build it as a library. |
| 884 expect(results, ['a2.dart']); | 874 expect(results, ['a2.dart']); |
| 885 expectGraph(node, ''' | 875 expectGraph(node, ''' |
| 886 index3.html | 876 index3.html |
| 887 |-- a2.dart | 877 |-- a2.dart |
| 888 | |-- a3.dart | 878 | |-- a3.dart |
| 889 | |-- a4.dart | 879 | |-- a4.dart |
| 890 | | |-- a10.dart | 880 | | |-- a10.dart |
| 891 | |-- a5.dart | 881 | |-- a5.dart |
| 892 | |-- a6.dart (part) | 882 | |-- a6.dart (part) |
| 893 $_RUNTIME_GRAPH | 883 $_RUNTIME_GRAPH |
| 894 '''); | 884 '''); |
| 895 | 885 |
| 896 a2.source.contents.modificationTime++; | 886 updateFile(a2.source, ''' |
| 897 a2.source.contents.data = ''' | |
| 898 library a2; | 887 library a2; |
| 899 import 'a3.dart'; | 888 import 'a3.dart'; |
| 900 import 'a4.dart'; | 889 import 'a4.dart'; |
| 901 import 'a6.dart'; // properly import it | 890 import 'a6.dart'; // properly import it |
| 902 export 'a5.dart'; | 891 export 'a5.dart'; |
| 903 '''; | 892 '''); |
| 904 results = []; | 893 results = []; |
| 905 rebuild(node, buildNoTransitiveChange); | 894 rebuild(node, buildNoTransitiveChange); |
| 906 // Note that a6 is now included, because we haven't built it as a | 895 // Note that a6 is now included, because we haven't built it as a |
| 907 // library until now: | 896 // library until now: |
| 908 expect(results, ['a6.dart', 'a2.dart', 'index3.html']); | 897 expect(results, ['a6.dart', 'a2.dart', 'index3.html']); |
| 909 | 898 |
| 910 a6.source.contents.modificationTime++; | 899 updateFile(a6.source); |
| 911 results = []; | 900 results = []; |
| 912 rebuild(node, buildNoTransitiveChange); | 901 rebuild(node, buildNoTransitiveChange); |
| 913 expect(results, ['a6.dart']); | 902 expect(results, ['a6.dart']); |
| 914 | 903 |
| 915 expectGraph(node, ''' | 904 expectGraph(node, ''' |
| 916 index3.html | 905 index3.html |
| 917 |-- a2.dart | 906 |-- a2.dart |
| 918 | |-- a3.dart | 907 | |-- a3.dart |
| 919 | |-- a4.dart | 908 | |-- a4.dart |
| 920 | | |-- a10.dart | 909 | | |-- a10.dart |
| (...skipping 14 matching lines...) Expand all Loading... |
| 935 index3.html | 924 index3.html |
| 936 |-- a2.dart | 925 |-- a2.dart |
| 937 | |-- a3.dart | 926 | |-- a3.dart |
| 938 | |-- a4.dart | 927 | |-- a4.dart |
| 939 | | |-- a10.dart | 928 | | |-- a10.dart |
| 940 | |-- a5.dart | 929 | |-- a5.dart |
| 941 | |-- a6.dart (part) | 930 | |-- a6.dart (part) |
| 942 $_RUNTIME_GRAPH | 931 $_RUNTIME_GRAPH |
| 943 '''); | 932 '''); |
| 944 | 933 |
| 945 a2.source.contents.modificationTime++; | 934 updateFile(a2.source, ''' |
| 946 a2.source.contents.data = ''' | |
| 947 library a2; | 935 library a2; |
| 948 import 'a3.dart'; | 936 import 'a3.dart'; |
| 949 import 'a4.dart'; | 937 import 'a4.dart'; |
| 950 import 'a6.dart'; // properly import it | 938 import 'a6.dart'; // properly import it |
| 951 export 'a5.dart'; | 939 export 'a5.dart'; |
| 952 '''; | 940 '''); |
| 953 results = []; | 941 results = []; |
| 954 rebuild(node, buildNoTransitiveChange); | 942 rebuild(node, buildNoTransitiveChange); |
| 955 expect(results, ['a6.dart', 'a2.dart', 'index3.html']); | 943 expect(results, ['a6.dart', 'a2.dart', 'index3.html']); |
| 956 expectGraph(node, ''' | 944 expectGraph(node, ''' |
| 957 index3.html | 945 index3.html |
| 958 |-- a2.dart | 946 |-- a2.dart |
| 959 | |-- a3.dart | 947 | |-- a3.dart |
| 960 | |-- a4.dart | 948 | |-- a4.dart |
| 961 | | |-- a10.dart | 949 | | |-- a10.dart |
| 962 | |-- a6.dart | 950 | |-- a6.dart |
| 963 | |-- a5.dart | 951 | |-- a5.dart |
| 964 $_RUNTIME_GRAPH | 952 $_RUNTIME_GRAPH |
| 965 '''); | 953 '''); |
| 966 | 954 |
| 967 a6.source.contents.modificationTime++; | 955 updateFile(a6.source, 'library a6; import "a5.dart";'); |
| 968 a6.source.contents.data = 'library a6; import "a5.dart";'; | |
| 969 results = []; | 956 results = []; |
| 970 rebuild(node, buildNoTransitiveChange); | 957 rebuild(node, buildNoTransitiveChange); |
| 971 expect(results, ['a6.dart', 'index3.html']); | 958 expect(results, ['a6.dart', 'index3.html']); |
| 972 expectGraph(node, ''' | 959 expectGraph(node, ''' |
| 973 index3.html | 960 index3.html |
| 974 |-- a2.dart | 961 |-- a2.dart |
| 975 | |-- a3.dart | 962 | |-- a3.dart |
| 976 | |-- a4.dart | 963 | |-- a4.dart |
| 977 | | |-- a10.dart | 964 | | |-- a10.dart |
| 978 | |-- a6.dart | 965 | |-- a6.dart |
| (...skipping 13 matching lines...) Expand all Loading... |
| 992 index3.html | 979 index3.html |
| 993 |-- a2.dart | 980 |-- a2.dart |
| 994 | |-- a3.dart | 981 | |-- a3.dart |
| 995 | |-- a4.dart | 982 | |-- a4.dart |
| 996 | | |-- a10.dart | 983 | | |-- a10.dart |
| 997 | |-- a5.dart | 984 | |-- a5.dart |
| 998 | |-- a6.dart (part) | 985 | |-- a6.dart (part) |
| 999 $_RUNTIME_GRAPH | 986 $_RUNTIME_GRAPH |
| 1000 '''); | 987 '''); |
| 1001 | 988 |
| 1002 a2.source.contents.modificationTime++; | 989 updateFile(a2.source, ''' |
| 1003 a2.source.contents.data = ''' | |
| 1004 library a2; | 990 library a2; |
| 1005 import 'a3.dart'; | 991 import 'a3.dart'; |
| 1006 import 'a4.dart'; | 992 import 'a4.dart'; |
| 1007 export 'a5.dart'; | 993 export 'a5.dart'; |
| 1008 '''; | 994 '''); |
| 1009 a6.source.contents.modificationTime++; | 995 updateFile(a6.source, 'library a6; import "a5.dart";'); |
| 1010 a6.source.contents.data = 'library a6; import "a5.dart";'; | |
| 1011 results = []; | 996 results = []; |
| 1012 rebuild(node, buildNoTransitiveChange); | 997 rebuild(node, buildNoTransitiveChange); |
| 1013 // a6 is not here, it's not reachable so we don't build it. | 998 // a6 is not here, it's not reachable so we don't build it. |
| 1014 expect(results, ['a2.dart', 'index3.html']); | 999 expect(results, ['a2.dart', 'index3.html']); |
| 1015 expectGraph(node, ''' | 1000 expectGraph(node, ''' |
| 1016 index3.html | 1001 index3.html |
| 1017 |-- a2.dart | 1002 |-- a2.dart |
| 1018 | |-- a3.dart | 1003 | |-- a3.dart |
| 1019 | |-- a4.dart | 1004 | |-- a4.dart |
| 1020 | | |-- a10.dart | 1005 | | |-- a10.dart |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1033 index3.html | 1018 index3.html |
| 1034 |-- a2.dart | 1019 |-- a2.dart |
| 1035 | |-- a3.dart | 1020 | |-- a3.dart |
| 1036 | |-- a4.dart | 1021 | |-- a4.dart |
| 1037 | | |-- a10.dart | 1022 | | |-- a10.dart |
| 1038 | |-- a5.dart | 1023 | |-- a5.dart |
| 1039 | |-- a6.dart (part) | 1024 | |-- a6.dart (part) |
| 1040 $_RUNTIME_GRAPH | 1025 $_RUNTIME_GRAPH |
| 1041 '''); | 1026 '''); |
| 1042 | 1027 |
| 1043 a2.source.contents.modificationTime++; | 1028 updateFile(a2.source, ''' |
| 1044 a2.source.contents.data = ''' | |
| 1045 library a2; | 1029 library a2; |
| 1046 import 'a3.dart'; | 1030 import 'a3.dart'; |
| 1047 import 'a4.dart'; | 1031 import 'a4.dart'; |
| 1048 part 'a5.dart'; // make it a part | 1032 part 'a5.dart'; // make it a part |
| 1049 part 'a6.dart'; | 1033 part 'a6.dart'; |
| 1050 '''; | 1034 '''); |
| 1051 results = []; | 1035 results = []; |
| 1052 rebuild(node, buildNoTransitiveChange); | 1036 rebuild(node, buildNoTransitiveChange); |
| 1053 expect(results, ['a2.dart', 'index3.html']); | 1037 expect(results, ['a2.dart', 'index3.html']); |
| 1054 expectGraph(node, ''' | 1038 expectGraph(node, ''' |
| 1055 index3.html | 1039 index3.html |
| 1056 |-- a2.dart | 1040 |-- a2.dart |
| 1057 | |-- a3.dart | 1041 | |-- a3.dart |
| 1058 | |-- a4.dart | 1042 | |-- a4.dart |
| 1059 | | |-- a10.dart | 1043 | | |-- a10.dart |
| 1060 | |-- a5.dart (part) | 1044 | |-- a5.dart (part) |
| 1061 | |-- a6.dart (part) | 1045 | |-- a6.dart (part) |
| 1062 $_RUNTIME_GRAPH | 1046 $_RUNTIME_GRAPH |
| 1063 '''); | 1047 '''); |
| 1064 | 1048 |
| 1065 a5.source.contents.modificationTime++; | 1049 updateFile(a5.source, 'part of a2;'); |
| 1066 a5.source.contents.data = 'part of a2;'; | |
| 1067 results = []; | 1050 results = []; |
| 1068 rebuild(node, buildNoTransitiveChange); | 1051 rebuild(node, buildNoTransitiveChange); |
| 1069 expect(results, ['a2.dart']); | 1052 expect(results, ['a2.dart']); |
| 1070 expectGraph(node, ''' | 1053 expectGraph(node, ''' |
| 1071 index3.html | 1054 index3.html |
| 1072 |-- a2.dart | 1055 |-- a2.dart |
| 1073 | |-- a3.dart | 1056 | |-- a3.dart |
| 1074 | |-- a4.dart | 1057 | |-- a4.dart |
| 1075 | | |-- a10.dart | 1058 | | |-- a10.dart |
| 1076 | |-- a5.dart (part) | 1059 | |-- a5.dart (part) |
| 1077 | |-- a6.dart (part) | 1060 | |-- a6.dart (part) |
| 1078 $_RUNTIME_GRAPH | 1061 $_RUNTIME_GRAPH |
| 1079 '''); | 1062 '''); |
| 1080 }); | 1063 }); |
| 1081 }); | 1064 }); |
| 1082 | 1065 |
| 1083 group('represented non-existing files', () { | 1066 group('represented non-existing files', () { |
| 1084 test('recognize locally change between existing and not-existing', () { | 1067 test('recognize locally change between existing and not-existing', () { |
| 1085 var n = nodeOf('/foo.dart'); | 1068 var n = nodeOf('/foo.dart'); |
| 1086 expect(n.source, isNotNull); | 1069 expect(n.source, isNotNull); |
| 1087 expect(n.source.exists(), isFalse); | 1070 expect(n.source.exists(), isFalse); |
| 1088 var source = testUriResolver.files[new Uri.file('/foo.dart')]; | 1071 var source = testUriResolver.resolveAbsolute(new Uri.file('/foo.dart')); |
| 1089 expect(n.source, source); | 1072 expect(n.source, source); |
| 1090 source.contents.data = "hi"; | 1073 updateFile(source, "hi"); |
| 1091 source.contents.modificationTime++; | |
| 1092 expect(n.source.exists(), isTrue); | 1074 expect(n.source.exists(), isTrue); |
| 1093 }); | 1075 }); |
| 1094 | 1076 |
| 1095 test('non-existing files are tracked in dependencies', () { | 1077 test('non-existing files are tracked in dependencies', () { |
| 1096 var node = nodeOf('/foo.dart'); | 1078 var node = nodeOf('/foo.dart'); |
| 1097 node.source.contents.data = "import 'bar.dart';"; | 1079 updateFile(node.source, "import 'bar.dart';"); |
| 1098 rebuild(node, buildNoTransitiveChange); | 1080 rebuild(node, buildNoTransitiveChange); |
| 1099 expect(node.allDeps.contains(nodeOf('/bar.dart')), isTrue); | 1081 expect(node.allDeps.contains(nodeOf('/bar.dart')), isTrue); |
| 1100 | 1082 |
| 1101 var source = nodeOf('/bar.dart').source; | 1083 var source = nodeOf('/bar.dart').source; |
| 1102 source.contents.data = "hi"; | 1084 updateFile(source, "hi"); |
| 1103 source.contents.modificationTime++; | |
| 1104 results = []; | 1085 results = []; |
| 1105 rebuild(node, buildWithTransitiveChange); | 1086 rebuild(node, buildWithTransitiveChange); |
| 1106 expect(results, ['bar.dart', 'foo.dart']); | 1087 expect(results, ['bar.dart', 'foo.dart']); |
| 1107 }); | 1088 }); |
| 1108 }); | 1089 }); |
| 1109 | 1090 |
| 1110 group('null for non-existing files', () { | 1091 group('null for non-existing files', () { |
| 1111 setUp(() { | 1092 setUp(() { |
| 1112 testUriResolver = new InMemoryUriResolver(testFiles, | |
| 1113 representNonExistingFiles: false); | |
| 1114 context = new TypeResolver.fromMock(mockSdkSources, options, | 1093 context = new TypeResolver.fromMock(mockSdkSources, options, |
| 1115 otherResolvers: [testUriResolver]).context; | 1094 otherResolvers: [testUriResolver]).context; |
| 1116 graph = new SourceGraph(context, new LogReporter(context), options); | 1095 graph = new SourceGraph(context, new LogReporter(context), options); |
| 1117 }); | 1096 }); |
| 1118 | 1097 |
| 1119 test('recognize locally change between existing and not-existing', () { | 1098 test('recognize locally change between existing and not-existing', () { |
| 1120 var n = nodeOf('/foo.dart'); | 1099 var n = nodeOf('/foo.dart'); |
| 1121 expect(n.source, isNull); | 1100 expect(n.source.exists(), isFalse); |
| 1122 var source = new InMemorySource(new Uri.file('/foo.dart'), "hi"); | 1101 var source = |
| 1123 testUriResolver.files[source.uri] = source; | 1102 testResourceProvider.newFile('/foo.dart', 'hi').createSource(); |
| 1124 expect(n.source, isNull); | 1103 expect( |
| 1125 n.update(); | 1104 testUriResolver.resolveAbsolute(new Uri.file('/foo.dart')), source); |
| 1126 expect(n.source, source); | 1105 expect(n.source, source); |
| 1127 expect(n.source.exists(), isTrue); | 1106 expect(n.source.exists(), isTrue); |
| 1107 n.update(); |
| 1128 expect(n.needsRebuild, isTrue); | 1108 expect(n.needsRebuild, isTrue); |
| 1129 }); | 1109 }); |
| 1130 | 1110 |
| 1131 test('non-existing files are tracked in dependencies', () { | 1111 test('non-existing files are tracked in dependencies', () { |
| 1132 var s1 = | 1112 var s1 = testResourceProvider |
| 1133 new InMemorySource(new Uri.file('/foo.dart'), "import 'bar.dart';"); | 1113 .newFile('/foo.dart', "import 'bar.dart';") |
| 1134 testUriResolver.files[s1.uri] = s1; | 1114 .createSource(); |
| 1135 var node = nodeOf('/foo.dart'); | 1115 var node = nodeOf('/foo.dart'); |
| 1136 rebuild(node, buildNoTransitiveChange); | 1116 rebuild(node, buildNoTransitiveChange); |
| 1137 expect(node.allDeps.length, 1); | 1117 expect(node.allDeps.length, 1); |
| 1138 expect(node.allDeps.contains(nodeOf('/bar.dart')), isTrue); | 1118 expect(node.allDeps.contains(nodeOf('/bar.dart')), isTrue); |
| 1139 expect(nodeOf('/bar.dart').source, isNull); | 1119 expect(nodeOf('/bar.dart').source.exists(), isFalse); |
| 1140 | 1120 |
| 1141 var s2 = new InMemorySource(new Uri.file('/bar.dart'), "hi"); | 1121 var s2 = testResourceProvider.newFile('/bar.dart', 'hi').createSource(); |
| 1142 testUriResolver.files[s2.uri] = s2; | |
| 1143 results = []; | 1122 results = []; |
| 1144 rebuild(node, buildWithTransitiveChange); | 1123 rebuild(node, buildWithTransitiveChange); |
| 1145 expect(results, ['bar.dart', 'foo.dart']); | 1124 expect(results, ['bar.dart', 'foo.dart']); |
| 1146 }); | 1125 }); |
| 1147 }); | 1126 }); |
| 1148 }); | 1127 }); |
| 1149 } | 1128 } |
| 1150 | 1129 |
| 1151 expectGraph(SourceNode node, String expectation) { | 1130 expectGraph(SourceNode node, String expectation) { |
| 1152 expect(printReachable(node), equalsIgnoringWhitespace(expectation)); | 1131 expect(printReachable(node), equalsIgnoringWhitespace(expectation)); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1190 helper(node); | 1169 helper(node); |
| 1191 return sb.toString(); | 1170 return sb.toString(); |
| 1192 } | 1171 } |
| 1193 | 1172 |
| 1194 final runtimeFilesWithoutPath = defaultRuntimeFiles | 1173 final runtimeFilesWithoutPath = defaultRuntimeFiles |
| 1195 .map((f) => f.replaceAll('dart/', '')) | 1174 .map((f) => f.replaceAll('dart/', '')) |
| 1196 .toList(growable: false); | 1175 .toList(growable: false); |
| 1197 final _RUNTIME_GRAPH = runtimeFilesWithoutPath.map((s) => '|-- $s').join('\n'); | 1176 final _RUNTIME_GRAPH = runtimeFilesWithoutPath.map((s) => '|-- $s').join('\n'); |
| 1198 final _RUNTIME_GRAPH_REBUILD = | 1177 final _RUNTIME_GRAPH_REBUILD = |
| 1199 runtimeFilesWithoutPath.map((s) => '|-- $s [needs-rebuild]').join('\n'); | 1178 runtimeFilesWithoutPath.map((s) => '|-- $s [needs-rebuild]').join('\n'); |
| 1200 | |
| 1201 bool _same(Set a, Set b) => a.length == b.length && a.containsAll(b); | |
| OLD | NEW |