OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library test.source.caching_pub_package_map_provider; |
| 6 |
| 7 import 'dart:convert'; |
| 8 import 'dart:io' as io; |
| 9 |
| 10 import 'package:analysis_server/src/source/caching_pub_package_map_provider.dart
'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/file_system/memory_file_system.dart'; |
| 13 import 'package:analyzer/source/package_map_provider.dart'; |
| 14 import 'package:analyzer/src/generated/sdk_io.dart'; |
| 15 import 'package:unittest/unittest.dart'; |
| 16 |
| 17 main() { |
| 18 groupSep = ' | '; |
| 19 |
| 20 group('CachingPubPackageMapProvider', () { |
| 21 MemoryResourceProvider resProvider; |
| 22 _MockPubListRunner mockRunner; |
| 23 |
| 24 Map result1 = { |
| 25 'packages': { |
| 26 'foo': '/tmp/proj1/packages/foo' |
| 27 }, |
| 28 'input_files': ['/tmp/proj1/pubspec.yaml'] |
| 29 }; |
| 30 |
| 31 Map result1error = { |
| 32 'input_files': ['/tmp/proj1/pubspec.lock'] |
| 33 }; |
| 34 |
| 35 Map result2 = { |
| 36 'packages': { |
| 37 'bar': '/tmp/proj2/packages/bar' |
| 38 }, |
| 39 'input_files': ['/tmp/proj2/pubspec.yaml'] |
| 40 }; |
| 41 |
| 42 Folder newProj(Map result) { |
| 43 Map packages = result['packages']; |
| 44 packages.forEach((String name, String path) { |
| 45 resProvider.newFolder(path); |
| 46 }); |
| 47 List<String> inputFiles = result['input_files']; |
| 48 for (String path in inputFiles) { |
| 49 resProvider.newFile(path, ''); |
| 50 } |
| 51 return resProvider.getResource(inputFiles[0]).parent; |
| 52 } |
| 53 |
| 54 int mockWriteFile(File cacheFile, String content) { |
| 55 if (!cacheFile.exists) { |
| 56 resProvider.newFolder(cacheFile.parent.path); |
| 57 resProvider.newFile(cacheFile.path, content); |
| 58 } else { |
| 59 resProvider.modifyFile(cacheFile.path, content); |
| 60 } |
| 61 Resource res = resProvider.getResource(cacheFile.path); |
| 62 if (res is File) { |
| 63 return res.createSource().modificationStamp; |
| 64 } |
| 65 throw 'expected file, but found $res'; |
| 66 } |
| 67 |
| 68 CachingPubPackageMapProvider newPkgProvider() { |
| 69 return new CachingPubPackageMapProvider( |
| 70 resProvider, |
| 71 DirectoryBasedDartSdk.defaultSdk, |
| 72 mockRunner.runPubList, |
| 73 mockWriteFile); |
| 74 } |
| 75 |
| 76 setUp(() { |
| 77 resProvider = new MemoryResourceProvider(); |
| 78 resProvider.newFolder('/tmp/proj/packages/foo'); |
| 79 mockRunner = new _MockPubListRunner(); |
| 80 }); |
| 81 |
| 82 group('computePackageMap', () { |
| 83 |
| 84 // Assert pub list called once and results are cached in memory |
| 85 test('cache memory', () { |
| 86 expect(mockRunner.runCount, 0); |
| 87 |
| 88 Folder folder1 = newProj(result1); |
| 89 CachingPubPackageMapProvider pkgProvider = newPkgProvider(); |
| 90 mockRunner.nextResult = JSON.encode(result1); |
| 91 PackageMapInfo info = pkgProvider.computePackageMap(folder1); |
| 92 expect(mockRunner.runCount, 1); |
| 93 _assertInfo(info, result1); |
| 94 |
| 95 info = pkgProvider.computePackageMap(folder1); |
| 96 expect(mockRunner.runCount, 1); |
| 97 _assertInfo(info, result1); |
| 98 }); |
| 99 |
| 100 // Assert pub list called once and results are cached on disk |
| 101 test('cache disk', () { |
| 102 expect(mockRunner.runCount, 0); |
| 103 |
| 104 Folder folder1 = newProj(result1); |
| 105 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider(); |
| 106 mockRunner.nextResult = JSON.encode(result1); |
| 107 PackageMapInfo info = pkgProvider1.computePackageMap(folder1); |
| 108 expect(mockRunner.runCount, 1); |
| 109 _assertInfo(info, result1); |
| 110 |
| 111 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider(); |
| 112 info = pkgProvider2.computePackageMap(folder1); |
| 113 expect(mockRunner.runCount, 1); |
| 114 _assertInfo(info, result1); |
| 115 }); |
| 116 |
| 117 // Assert modification in one shows up in the other |
| 118 test('shared disk cache', () { |
| 119 expect(mockRunner.runCount, 0); |
| 120 |
| 121 Folder folder1 = newProj(result1); |
| 122 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider(); |
| 123 mockRunner.nextResult = JSON.encode(result1); |
| 124 PackageMapInfo info = pkgProvider1.computePackageMap(folder1); |
| 125 expect(mockRunner.runCount, 1); |
| 126 _assertInfo(info, result1); |
| 127 |
| 128 Folder folder2 = newProj(result2); |
| 129 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider(); |
| 130 mockRunner.nextResult = JSON.encode(result2); |
| 131 info = pkgProvider2.computePackageMap(folder2); |
| 132 expect(mockRunner.runCount, 2); |
| 133 _assertInfo(info, result2); |
| 134 |
| 135 info = pkgProvider1.computePackageMap(folder2); |
| 136 expect(mockRunner.runCount, 2); |
| 137 _assertInfo(info, result2); |
| 138 }); |
| 139 |
| 140 // Assert pub list called again if input file modified |
| 141 test('input file changed', () { |
| 142 expect(mockRunner.runCount, 0); |
| 143 |
| 144 Folder folder1 = newProj(result1); |
| 145 CachingPubPackageMapProvider pkgProvider = newPkgProvider(); |
| 146 mockRunner.nextResult = JSON.encode(result1); |
| 147 PackageMapInfo info = pkgProvider.computePackageMap(folder1); |
| 148 expect(mockRunner.runCount, 1); |
| 149 _assertInfo(info, result1); |
| 150 |
| 151 resProvider.modifyFile(info.dependencies.first, 'new content'); |
| 152 mockRunner.nextResult = JSON.encode(result1); |
| 153 info = pkgProvider.computePackageMap(folder1); |
| 154 expect(mockRunner.runCount, 2); |
| 155 _assertInfo(info, result1); |
| 156 }); |
| 157 |
| 158 // Assert pub list called again if input file modified |
| 159 // after reloading package provider cache from disk |
| 160 test('input file changed 2', () { |
| 161 expect(mockRunner.runCount, 0); |
| 162 |
| 163 Folder folder1 = newProj(result1); |
| 164 CachingPubPackageMapProvider pkgProvider1 = newPkgProvider(); |
| 165 mockRunner.nextResult = JSON.encode(result1); |
| 166 PackageMapInfo info = pkgProvider1.computePackageMap(folder1); |
| 167 expect(mockRunner.runCount, 1); |
| 168 _assertInfo(info, result1); |
| 169 |
| 170 resProvider.modifyFile(info.dependencies.first, 'new content'); |
| 171 mockRunner.nextResult = JSON.encode(result1); |
| 172 CachingPubPackageMapProvider pkgProvider2 = newPkgProvider(); |
| 173 info = pkgProvider2.computePackageMap(folder1); |
| 174 expect(mockRunner.runCount, 2); |
| 175 _assertInfo(info, result1); |
| 176 }); |
| 177 |
| 178 // Assert pub list called again if input file deleted |
| 179 test('input file deleted', () { |
| 180 expect(mockRunner.runCount, 0); |
| 181 |
| 182 Folder folder1 = newProj(result1); |
| 183 CachingPubPackageMapProvider pkgProvider = newPkgProvider(); |
| 184 mockRunner.nextResult = JSON.encode(result1); |
| 185 PackageMapInfo info = pkgProvider.computePackageMap(folder1); |
| 186 expect(mockRunner.runCount, 1); |
| 187 _assertInfo(info, result1); |
| 188 |
| 189 resProvider.deleteFile(info.dependencies.first); |
| 190 mockRunner.nextResult = JSON.encode(result1); |
| 191 info = pkgProvider.computePackageMap(folder1); |
| 192 expect(mockRunner.runCount, 2); |
| 193 _assertInfo(info, result1); |
| 194 }); |
| 195 |
| 196 // Assert pub list not called if folder does not exist |
| 197 // and returns same cached result if folder restored as before |
| 198 test('project removed then restored', () { |
| 199 expect(mockRunner.runCount, 0); |
| 200 |
| 201 Folder folder1 = newProj(result1); |
| 202 CachingPubPackageMapProvider pkgProvider = newPkgProvider(); |
| 203 mockRunner.nextResult = JSON.encode(result1); |
| 204 PackageMapInfo info = pkgProvider.computePackageMap(folder1); |
| 205 expect(mockRunner.runCount, 1); |
| 206 _assertInfo(info, result1); |
| 207 |
| 208 var restorePoint = resProvider.clear(); |
| 209 info = pkgProvider.computePackageMap(folder1); |
| 210 expect(mockRunner.runCount, 1); |
| 211 _assertError(info, result1error); |
| 212 |
| 213 resProvider.restore(restorePoint); |
| 214 info = pkgProvider.computePackageMap(folder1); |
| 215 expect(mockRunner.runCount, 1); |
| 216 _assertInfo(info, result1); |
| 217 }); |
| 218 }); |
| 219 }); |
| 220 } |
| 221 |
| 222 _assertInfo(PackageMapInfo info, Map expected) { |
| 223 Map<String, String> expectedPackages = expected['packages']; |
| 224 expect(info.packageMap, hasLength(expectedPackages.length)); |
| 225 for (String key in expectedPackages.keys) { |
| 226 List<Folder> packageList = info.packageMap[key]; |
| 227 expect(packageList, hasLength(1)); |
| 228 expect(packageList[0].path, expectedPackages[key]); |
| 229 } |
| 230 List<String> expectedFiles = expected['input_files']; |
| 231 expect(info.dependencies, hasLength(expectedFiles.length)); |
| 232 for (String path in expectedFiles) { |
| 233 expect(info.dependencies, contains(path)); |
| 234 } |
| 235 } |
| 236 |
| 237 _assertError(PackageMapInfo info, Map expected) { |
| 238 expect(info.packageMap, isNull); |
| 239 List<String> expectedFiles = expected['input_files']; |
| 240 expect(info.dependencies, hasLength(expectedFiles.length)); |
| 241 for (String path in expectedFiles) { |
| 242 expect(info.dependencies, contains(path)); |
| 243 } |
| 244 } |
| 245 |
| 246 /** |
| 247 * Mock for simulating and tracking execution of pub list |
| 248 */ |
| 249 class _MockPubListRunner { |
| 250 int runCount = 0; |
| 251 String nextResult; |
| 252 |
| 253 io.ProcessResult runPubList(Folder folder) { |
| 254 if (nextResult == null) { |
| 255 throw 'missing nextResult'; |
| 256 } |
| 257 |
| 258 ++runCount; |
| 259 String result = nextResult; |
| 260 nextResult = null; |
| 261 return new _MockResult(result); |
| 262 } |
| 263 } |
| 264 |
| 265 class _MockResult implements io.ProcessResult { |
| 266 String result; |
| 267 |
| 268 _MockResult(this.result); |
| 269 |
| 270 @override |
| 271 int get exitCode => 0; |
| 272 |
| 273 // TODO: implement stdout |
| 274 @override |
| 275 get stdout => result; |
| 276 |
| 277 noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); |
| 278 } |
OLD | NEW |