OLD | NEW |
| (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 import 'dart:async'; | |
6 import 'dart:convert'; | |
7 | |
8 import 'package:http/http.dart' as http; | |
9 import 'package:http/testing.dart'; | |
10 import 'package:path/path.dart' as path; | |
11 import 'package:scheduled_test/scheduled_test.dart'; | |
12 | |
13 import '../../lib/src/entrypoint.dart'; | |
14 import '../../lib/src/validator.dart'; | |
15 import '../../lib/src/validator/dependency.dart'; | |
16 import '../descriptor.dart' as d; | |
17 import '../test_pub.dart'; | |
18 import 'utils.dart'; | |
19 | |
20 Validator dependency(Entrypoint entrypoint) => | |
21 new DependencyValidator(entrypoint); | |
22 | |
23 expectDependencyValidationError(String error) { | |
24 expect( | |
25 schedulePackageValidation(dependency), | |
26 completion(pairOf(anyElement(contains(error)), isEmpty))); | |
27 } | |
28 | |
29 expectDependencyValidationWarning(String warning) { | |
30 expect( | |
31 schedulePackageValidation(dependency), | |
32 completion(pairOf(isEmpty, anyElement(contains(warning))))); | |
33 } | |
34 | |
35 /// Sets up a test package with dependency [dep] and mocks a server with | |
36 /// [hostedVersions] of the package available. | |
37 setUpDependency(Map dep, {List<String> hostedVersions}) { | |
38 useMockClient(new MockClient((request) { | |
39 expect(request.method, equals("GET")); | |
40 expect(request.url.path, equals("/api/packages/foo")); | |
41 | |
42 if (hostedVersions == null) { | |
43 return new Future.value(new http.Response("not found", 404)); | |
44 } else { | |
45 return new Future.value(new http.Response(JSON.encode({ | |
46 "name": "foo", | |
47 "uploaders": ["nweiz@google.com"], | |
48 "versions": hostedVersions.map( | |
49 (version) => packageVersionApiMap(packageMap('foo', version))).toLis
t() | |
50 }), 200)); | |
51 } | |
52 })); | |
53 | |
54 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
55 "foo": dep | |
56 })]).create(); | |
57 } | |
58 | |
59 main() { | |
60 initConfig(); | |
61 | |
62 group('should consider a package valid if it', () { | |
63 integration('looks normal', () { | |
64 d.validPackage.create(); | |
65 expectNoValidationError(dependency); | |
66 }); | |
67 | |
68 integration('has a ^ constraint with an appropriate SDK constraint', () { | |
69 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
70 "foo": "^1.2.3" | |
71 }, sdk: ">=1.8.0 <2.0.0")]).create(); | |
72 expectNoValidationError(dependency); | |
73 }); | |
74 }); | |
75 | |
76 group('should consider a package invalid if it', () { | |
77 setUp(d.validPackage.create); | |
78 | |
79 group('has a git dependency', () { | |
80 group('where a hosted version exists', () { | |
81 integration("and should suggest the hosted primary version", () { | |
82 setUpDependency({ | |
83 'git': 'git://github.com/dart-lang/foo' | |
84 }, hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]); | |
85 expectDependencyValidationWarning(' foo: ">=2.0.0 <3.0.0"'); | |
86 }); | |
87 | |
88 integration( | |
89 "and should suggest the hosted prerelease version if " | |
90 "it's the only version available", | |
91 () { | |
92 setUpDependency({ | |
93 'git': 'git://github.com/dart-lang/foo' | |
94 }, hostedVersions: ["3.0.0-pre", "2.0.0-pre"]); | |
95 expectDependencyValidationWarning(' foo: ">=3.0.0-pre <4.0.0"'); | |
96 }); | |
97 | |
98 integration( | |
99 "and should suggest a tighter constraint if primary is " "pre-1.0.0"
, | |
100 () { | |
101 setUpDependency({ | |
102 'git': 'git://github.com/dart-lang/foo' | |
103 }, hostedVersions: ["0.0.1", "0.0.2"]); | |
104 expectDependencyValidationWarning(' foo: ">=0.0.2 <0.1.0"'); | |
105 }); | |
106 }); | |
107 | |
108 group('where no hosted version exists', () { | |
109 integration("and should use the other source's version", () { | |
110 setUpDependency({ | |
111 'git': 'git://github.com/dart-lang/foo', | |
112 'version': '>=1.0.0 <2.0.0' | |
113 }); | |
114 expectDependencyValidationWarning(' foo: ">=1.0.0 <2.0.0"'); | |
115 }); | |
116 | |
117 integration( | |
118 "and should use the other source's unquoted version if " "concrete", | |
119 () { | |
120 setUpDependency({ | |
121 'git': 'git://github.com/dart-lang/foo', | |
122 'version': '0.2.3' | |
123 }); | |
124 expectDependencyValidationWarning(' foo: 0.2.3'); | |
125 }); | |
126 }); | |
127 }); | |
128 | |
129 group('has a path dependency', () { | |
130 group('where a hosted version exists', () { | |
131 integration("and should suggest the hosted primary version", () { | |
132 setUpDependency({ | |
133 'path': path.join(sandboxDir, 'foo') | |
134 }, hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]); | |
135 expectDependencyValidationError(' foo: ">=2.0.0 <3.0.0"'); | |
136 }); | |
137 | |
138 integration( | |
139 "and should suggest the hosted prerelease version if " | |
140 "it's the only version available", | |
141 () { | |
142 setUpDependency({ | |
143 'path': path.join(sandboxDir, 'foo') | |
144 }, hostedVersions: ["3.0.0-pre", "2.0.0-pre"]); | |
145 expectDependencyValidationError(' foo: ">=3.0.0-pre <4.0.0"'); | |
146 }); | |
147 | |
148 integration( | |
149 "and should suggest a tighter constraint if primary is " "pre-1.0.0"
, | |
150 () { | |
151 setUpDependency({ | |
152 'path': path.join(sandboxDir, 'foo') | |
153 }, hostedVersions: ["0.0.1", "0.0.2"]); | |
154 expectDependencyValidationError(' foo: ">=0.0.2 <0.1.0"'); | |
155 }); | |
156 }); | |
157 | |
158 group('where no hosted version exists', () { | |
159 integration("and should use the other source's version", () { | |
160 setUpDependency({ | |
161 'path': path.join(sandboxDir, 'foo'), | |
162 'version': '>=1.0.0 <2.0.0' | |
163 }); | |
164 expectDependencyValidationError(' foo: ">=1.0.0 <2.0.0"'); | |
165 }); | |
166 | |
167 integration( | |
168 "and should use the other source's unquoted version if " "concrete", | |
169 () { | |
170 setUpDependency({ | |
171 'path': path.join(sandboxDir, 'foo'), | |
172 'version': '0.2.3' | |
173 }); | |
174 expectDependencyValidationError(' foo: 0.2.3'); | |
175 }); | |
176 }); | |
177 }); | |
178 | |
179 group('has an unconstrained dependency', () { | |
180 group('and it should not suggest a version', () { | |
181 integration("if there's no lockfile", () { | |
182 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
183 "foo": "any" | |
184 })]).create(); | |
185 | |
186 expect( | |
187 schedulePackageValidation(dependency), | |
188 completion(pairOf(isEmpty, everyElement(isNot(contains("\n foo:")
))))); | |
189 }); | |
190 | |
191 integration( | |
192 "if the lockfile doesn't have an entry for the " "dependency", | |
193 () { | |
194 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
195 "foo": "any" | |
196 }), d.file("pubspec.lock", JSON.encode({ | |
197 'packages': { | |
198 'bar': { | |
199 'version': '1.2.3', | |
200 'source': 'hosted', | |
201 'description': { | |
202 'name': 'bar', | |
203 'url': 'http://pub.dartlang.org' | |
204 } | |
205 } | |
206 } | |
207 }))]).create(); | |
208 | |
209 expect( | |
210 schedulePackageValidation(dependency), | |
211 completion(pairOf(isEmpty, everyElement(isNot(contains("\n foo:")
))))); | |
212 }); | |
213 }); | |
214 | |
215 group('with a lockfile', () { | |
216 integration( | |
217 'and it should suggest a constraint based on the locked ' 'version', | |
218 () { | |
219 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
220 "foo": "any" | |
221 }), d.file("pubspec.lock", JSON.encode({ | |
222 'packages': { | |
223 'foo': { | |
224 'version': '1.2.3', | |
225 'source': 'hosted', | |
226 'description': { | |
227 'name': 'foo', | |
228 'url': 'http://pub.dartlang.org' | |
229 } | |
230 } | |
231 } | |
232 }))]).create(); | |
233 | |
234 expectDependencyValidationWarning(' foo: ">=1.2.3 <2.0.0"'); | |
235 }); | |
236 | |
237 integration( | |
238 'and it should suggest a concrete constraint if the locked ' | |
239 'version is pre-1.0.0', | |
240 () { | |
241 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
242 "foo": "any" | |
243 }), d.file("pubspec.lock", JSON.encode({ | |
244 'packages': { | |
245 'foo': { | |
246 'version': '0.1.2', | |
247 'source': 'hosted', | |
248 'description': { | |
249 'name': 'foo', | |
250 'url': 'http://pub.dartlang.org' | |
251 } | |
252 } | |
253 } | |
254 }))]).create(); | |
255 | |
256 expectDependencyValidationWarning(' foo: ">=0.1.2 <0.2.0"'); | |
257 }); | |
258 }); | |
259 }); | |
260 | |
261 integration( | |
262 'with a single-version dependency and it should suggest a ' | |
263 'constraint based on the version', | |
264 () { | |
265 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
266 "foo": "1.2.3" | |
267 })]).create(); | |
268 | |
269 expectDependencyValidationWarning(' foo: ">=1.2.3 <2.0.0"'); | |
270 }); | |
271 | |
272 group('has a dependency without a lower bound', () { | |
273 group('and it should not suggest a version', () { | |
274 integration("if there's no lockfile", () { | |
275 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
276 "foo": "<3.0.0" | |
277 })]).create(); | |
278 | |
279 expect( | |
280 schedulePackageValidation(dependency), | |
281 completion(pairOf(isEmpty, everyElement(isNot(contains("\n foo:")
))))); | |
282 }); | |
283 | |
284 integration( | |
285 "if the lockfile doesn't have an entry for the " "dependency", | |
286 () { | |
287 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
288 "foo": "<3.0.0" | |
289 }), d.file("pubspec.lock", JSON.encode({ | |
290 'packages': { | |
291 'bar': { | |
292 'version': '1.2.3', | |
293 'source': 'hosted', | |
294 'description': { | |
295 'name': 'bar', | |
296 'url': 'http://pub.dartlang.org' | |
297 } | |
298 } | |
299 } | |
300 }))]).create(); | |
301 | |
302 expect( | |
303 schedulePackageValidation(dependency), | |
304 completion(pairOf(isEmpty, everyElement(isNot(contains("\n foo:")
))))); | |
305 }); | |
306 }); | |
307 | |
308 group('with a lockfile', () { | |
309 integration( | |
310 'and it should suggest a constraint based on the locked ' 'version', | |
311 () { | |
312 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
313 "foo": "<3.0.0" | |
314 }), d.file("pubspec.lock", JSON.encode({ | |
315 'packages': { | |
316 'foo': { | |
317 'version': '1.2.3', | |
318 'source': 'hosted', | |
319 'description': { | |
320 'name': 'foo', | |
321 'url': 'http://pub.dartlang.org' | |
322 } | |
323 } | |
324 } | |
325 }))]).create(); | |
326 | |
327 expectDependencyValidationWarning(' foo: ">=1.2.3 <3.0.0"'); | |
328 }); | |
329 | |
330 integration('and it should preserve the upper-bound operator', () { | |
331 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
332 "foo": "<=3.0.0" | |
333 }), d.file("pubspec.lock", JSON.encode({ | |
334 'packages': { | |
335 'foo': { | |
336 'version': '1.2.3', | |
337 'source': 'hosted', | |
338 'description': { | |
339 'name': 'foo', | |
340 'url': 'http://pub.dartlang.org' | |
341 } | |
342 } | |
343 } | |
344 }))]).create(); | |
345 | |
346 expectDependencyValidationWarning(' foo: ">=1.2.3 <=3.0.0"'); | |
347 }); | |
348 | |
349 integration( | |
350 'and it should expand the suggested constraint if the ' | |
351 'locked version matches the upper bound', | |
352 () { | |
353 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
354 "foo": "<=1.2.3" | |
355 }), d.file("pubspec.lock", JSON.encode({ | |
356 'packages': { | |
357 'foo': { | |
358 'version': '1.2.3', | |
359 'source': 'hosted', | |
360 'description': { | |
361 'name': 'foo', | |
362 'url': 'http://pub.dartlang.org' | |
363 } | |
364 } | |
365 } | |
366 }))]).create(); | |
367 | |
368 expectDependencyValidationWarning(' foo: ">=1.2.3 <2.0.0"'); | |
369 }); | |
370 }); | |
371 }); | |
372 | |
373 group('with a dependency without an upper bound', () { | |
374 integration( | |
375 'and it should suggest a constraint based on the lower bound', | |
376 () { | |
377 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
378 "foo": ">=1.2.3" | |
379 })]).create(); | |
380 | |
381 expectDependencyValidationWarning(' foo: ">=1.2.3 <2.0.0"'); | |
382 }); | |
383 | |
384 integration('and it should preserve the lower-bound operator', () { | |
385 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
386 "foo": ">1.2.3" | |
387 })]).create(); | |
388 | |
389 expectDependencyValidationWarning(' foo: ">1.2.3 <2.0.0"'); | |
390 }); | |
391 }); | |
392 | |
393 group('has a ^ dependency', () { | |
394 integration("without an SDK constraint", () { | |
395 d.dir(appPath, [d.libPubspec("integration_pkg", "1.0.0", deps: { | |
396 "foo": "^1.2.3" | |
397 })]).create(); | |
398 | |
399 expectDependencyValidationError(' foo: ">=1.2.3 <2.0.0"'); | |
400 }); | |
401 | |
402 integration("with a too-broad SDK constraint", () { | |
403 d.dir(appPath, [d.libPubspec("test_pkg", "1.0.0", deps: { | |
404 "foo": "^1.2.3" | |
405 }, sdk: ">=1.5.0 <2.0.0")]).create(); | |
406 | |
407 expectDependencyValidationError(' foo: ">=1.2.3 <2.0.0"'); | |
408 }); | |
409 }); | |
410 }); | |
411 } | |
OLD | NEW |