1 //! Tests for supporting older versions of the Cargo.lock file format.
2
3 use cargo_test_support::compare::assert_match_exact;
4 use cargo_test_support::git;
5 use cargo_test_support::registry::Package;
6 use cargo_test_support::{basic_lib_manifest, basic_manifest, project};
7
8 #[cargo_test]
oldest_lockfile_still_works()9 fn oldest_lockfile_still_works() {
10 let cargo_commands = vec!["build", "update"];
11 for cargo_command in cargo_commands {
12 oldest_lockfile_still_works_with_command(cargo_command);
13 }
14 }
15
oldest_lockfile_still_works_with_command(cargo_command: &str)16 fn oldest_lockfile_still_works_with_command(cargo_command: &str) {
17 Package::new("bar", "0.1.0").publish();
18
19 let expected_lockfile = r#"# This file is automatically @generated by Cargo.
20 # It is not intended for manual editing.
21 version = 3
22
23 [[package]]
24 name = "bar"
25 version = "0.1.0"
26 source = "registry+https://github.com/rust-lang/crates.io-index"
27 checksum = "[..]"
28
29 [[package]]
30 name = "foo"
31 version = "0.0.1"
32 dependencies = [
33 "bar",
34 ]
35 "#;
36
37 let old_lockfile = r#"
38 [root]
39 name = "foo"
40 version = "0.0.1"
41 dependencies = [
42 "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
43 ]
44
45 [[package]]
46 name = "bar"
47 version = "0.1.0"
48 source = "registry+https://github.com/rust-lang/crates.io-index"
49 "#;
50
51 let p = project()
52 .file(
53 "Cargo.toml",
54 r#"
55 [project]
56 name = "foo"
57 version = "0.0.1"
58 authors = []
59
60 [dependencies]
61 bar = "0.1.0"
62 "#,
63 )
64 .file("src/lib.rs", "")
65 .file("Cargo.lock", old_lockfile)
66 .build();
67
68 p.cargo(cargo_command).run();
69
70 let lock = p.read_lockfile();
71 assert_match_exact(expected_lockfile, &lock);
72 }
73
74 #[cargo_test]
frozen_flag_preserves_old_lockfile()75 fn frozen_flag_preserves_old_lockfile() {
76 let cksum = Package::new("bar", "0.1.0").publish();
77
78 let old_lockfile = format!(
79 r#"[root]
80 name = "foo"
81 version = "0.0.1"
82 dependencies = [
83 "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
84 ]
85
86 [[package]]
87 name = "bar"
88 version = "0.1.0"
89 source = "registry+https://github.com/rust-lang/crates.io-index"
90
91 [metadata]
92 "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}"
93 "#,
94 cksum,
95 );
96
97 let p = project()
98 .file(
99 "Cargo.toml",
100 r#"
101 [project]
102 name = "foo"
103 version = "0.0.1"
104 authors = []
105
106 [dependencies]
107 bar = "0.1.0"
108 "#,
109 )
110 .file("src/lib.rs", "")
111 .file("Cargo.lock", &old_lockfile)
112 .build();
113
114 p.cargo("build --locked").run();
115
116 let lock = p.read_lockfile();
117 assert_match_exact(&old_lockfile, &lock);
118 }
119
120 #[cargo_test]
totally_wild_checksums_works()121 fn totally_wild_checksums_works() {
122 Package::new("bar", "0.1.0").publish();
123
124 let p = project()
125 .file(
126 "Cargo.toml",
127 r#"
128 [project]
129 name = "foo"
130 version = "0.0.1"
131 authors = []
132
133 [dependencies]
134 bar = "0.1.0"
135 "#,
136 )
137 .file("src/lib.rs", "")
138 .file(
139 "Cargo.lock",
140 r#"
141 [[package]]
142 name = "foo"
143 version = "0.0.1"
144 dependencies = [
145 "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
146 ]
147
148 [[package]]
149 name = "bar"
150 version = "0.1.0"
151 source = "registry+https://github.com/rust-lang/crates.io-index"
152
153 [metadata]
154 "checksum baz 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
155 "checksum bar 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
156 "#,
157 );
158
159 let p = p.build();
160
161 p.cargo("build").run();
162
163 let lock = p.read_lockfile();
164 assert_match_exact(
165 r#"# This file is automatically @generated by Cargo.
166 # It is not intended for manual editing.
167 version = 3
168
169 [[package]]
170 name = "bar"
171 version = "0.1.0"
172 source = "registry+https://github.com/rust-lang/crates.io-index"
173 checksum = "[..]"
174
175 [[package]]
176 name = "foo"
177 version = "0.0.1"
178 dependencies = [
179 "bar",
180 ]
181 "#,
182 &lock,
183 );
184 }
185
186 #[cargo_test]
wrong_checksum_is_an_error()187 fn wrong_checksum_is_an_error() {
188 Package::new("bar", "0.1.0").publish();
189
190 let p = project()
191 .file(
192 "Cargo.toml",
193 r#"
194 [project]
195 name = "foo"
196 version = "0.0.1"
197 authors = []
198
199 [dependencies]
200 bar = "0.1.0"
201 "#,
202 )
203 .file("src/lib.rs", "")
204 .file(
205 "Cargo.lock",
206 r#"
207 [[package]]
208 name = "foo"
209 version = "0.0.1"
210 dependencies = [
211 "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
212 ]
213
214 [[package]]
215 name = "bar"
216 version = "0.1.0"
217 source = "registry+https://github.com/rust-lang/crates.io-index"
218
219 [metadata]
220 "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
221 "#,
222 );
223
224 let p = p.build();
225
226 p.cargo("build")
227 .with_status(101)
228 .with_stderr(
229 "\
230 [UPDATING] `[..]` index
231 error: checksum for `bar v0.1.0` changed between lock files
232
233 this could be indicative of a few possible errors:
234
235 * the lock file is corrupt
236 * a replacement source in use (e.g., a mirror) returned a different checksum
237 * the source itself may be corrupt in one way or another
238
239 unable to verify that `bar v0.1.0` is the same as when the lockfile was generated
240
241 ",
242 )
243 .run();
244 }
245
246 // If the checksum is unlisted in the lock file (e.g., <none>) yet we can
247 // calculate it (e.g., it's a registry dep), then we should in theory just fill
248 // it in.
249 #[cargo_test]
unlisted_checksum_is_bad_if_we_calculate()250 fn unlisted_checksum_is_bad_if_we_calculate() {
251 Package::new("bar", "0.1.0").publish();
252
253 let p = project()
254 .file(
255 "Cargo.toml",
256 r#"
257 [project]
258 name = "foo"
259 version = "0.0.1"
260 authors = []
261
262 [dependencies]
263 bar = "0.1.0"
264 "#,
265 )
266 .file("src/lib.rs", "")
267 .file(
268 "Cargo.lock",
269 r#"
270 [[package]]
271 name = "foo"
272 version = "0.0.1"
273 dependencies = [
274 "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
275 ]
276
277 [[package]]
278 name = "bar"
279 version = "0.1.0"
280 source = "registry+https://github.com/rust-lang/crates.io-index"
281
282 [metadata]
283 "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "<none>"
284 "#,
285 );
286 let p = p.build();
287
288 p.cargo("fetch")
289 .with_status(101)
290 .with_stderr(
291 "\
292 [UPDATING] `[..]` index
293 error: checksum for `bar v0.1.0` was not previously calculated, but a checksum \
294 could now be calculated
295
296 this could be indicative of a few possible situations:
297
298 * the source `[..]` did not previously support checksums,
299 but was replaced with one that does
300 * newer Cargo implementations know how to checksum this source, but this
301 older implementation does not
302 * the lock file is corrupt
303
304 ",
305 )
306 .run();
307 }
308
309 // If the checksum is listed in the lock file yet we cannot calculate it (e.g.,
310 // Git dependencies as of today), then make sure we choke.
311 #[cargo_test]
listed_checksum_bad_if_we_cannot_compute()312 fn listed_checksum_bad_if_we_cannot_compute() {
313 let git = git::new("bar", |p| {
314 p.file("Cargo.toml", &basic_manifest("bar", "0.1.0"))
315 .file("src/lib.rs", "")
316 });
317
318 let p = project()
319 .file(
320 "Cargo.toml",
321 &format!(
322 r#"
323 [project]
324 name = "foo"
325 version = "0.0.1"
326 authors = []
327
328 [dependencies]
329 bar = {{ git = '{}' }}
330 "#,
331 git.url()
332 ),
333 )
334 .file("src/lib.rs", "")
335 .file(
336 "Cargo.lock",
337 &format!(
338 r#"
339 [[package]]
340 name = "foo"
341 version = "0.0.1"
342 dependencies = [
343 "bar 0.1.0 (git+{0})"
344 ]
345
346 [[package]]
347 name = "bar"
348 version = "0.1.0"
349 source = "git+{0}"
350
351 [metadata]
352 "checksum bar 0.1.0 (git+{0})" = "checksum"
353 "#,
354 git.url()
355 ),
356 );
357
358 let p = p.build();
359
360 p.cargo("fetch")
361 .with_status(101)
362 .with_stderr(
363 "\
364 [UPDATING] git repository `[..]`
365 error: checksum for `bar v0.1.0 ([..])` could not be calculated, but a \
366 checksum is listed in the existing lock file[..]
367
368 this could be indicative of a few possible situations:
369
370 * the source `[..]` supports checksums,
371 but was replaced with one that doesn't
372 * the lock file is corrupt
373
374 unable to verify that `bar v0.1.0 ([..])` is the same as when the lockfile was generated
375
376 ",
377 )
378 .run();
379 }
380
381 #[cargo_test]
current_lockfile_format()382 fn current_lockfile_format() {
383 Package::new("bar", "0.1.0").publish();
384
385 let p = project()
386 .file(
387 "Cargo.toml",
388 r#"
389 [package]
390 name = "foo"
391 version = "0.0.1"
392 authors = []
393
394 [dependencies]
395 bar = "0.1.0"
396 "#,
397 )
398 .file("src/lib.rs", "");
399 let p = p.build();
400
401 p.cargo("build").run();
402
403 let actual = p.read_lockfile();
404
405 let expected = "\
406 # This file is automatically @generated by Cargo.\n# It is not intended for manual editing.
407 version = 3
408
409 [[package]]
410 name = \"bar\"
411 version = \"0.1.0\"
412 source = \"registry+https://github.com/rust-lang/crates.io-index\"
413 checksum = \"[..]\"
414
415 [[package]]
416 name = \"foo\"
417 version = \"0.0.1\"
418 dependencies = [
419 \"bar\",
420 ]
421 ";
422 assert_match_exact(expected, &actual);
423 }
424
425 #[cargo_test]
lockfile_without_root()426 fn lockfile_without_root() {
427 Package::new("bar", "0.1.0").publish();
428
429 let lockfile = r#"
430 # This file is automatically @generated by Cargo.
431 # It is not intended for manual editing.
432 [[package]]
433 name = "bar"
434 version = "0.1.0"
435 source = "registry+https://github.com/rust-lang/crates.io-index"
436
437 [[package]]
438 name = "foo"
439 version = "0.0.1"
440 dependencies = [
441 "bar",
442 ]
443 "#;
444
445 let p = project()
446 .file(
447 "Cargo.toml",
448 r#"
449 [package]
450 name = "foo"
451 version = "0.0.1"
452 authors = []
453
454 [dependencies]
455 bar = "0.1.0"
456 "#,
457 )
458 .file("src/lib.rs", "")
459 .file("Cargo.lock", lockfile);
460
461 let p = p.build();
462
463 p.cargo("build").run();
464
465 let lock = p.read_lockfile();
466 assert_match_exact(
467 r#"# [..]
468 # [..]
469 version = 3
470
471 [[package]]
472 name = "bar"
473 version = "0.1.0"
474 source = "registry+https://github.com/rust-lang/crates.io-index"
475 checksum = "[..]"
476
477 [[package]]
478 name = "foo"
479 version = "0.0.1"
480 dependencies = [
481 "bar",
482 ]
483 "#,
484 &lock,
485 );
486 }
487
488 #[cargo_test]
locked_correct_error()489 fn locked_correct_error() {
490 Package::new("bar", "0.1.0").publish();
491
492 let p = project()
493 .file(
494 "Cargo.toml",
495 r#"
496 [project]
497 name = "foo"
498 version = "0.0.1"
499 authors = []
500
501 [dependencies]
502 bar = "0.1.0"
503 "#,
504 )
505 .file("src/lib.rs", "");
506 let p = p.build();
507
508 p.cargo("build --locked")
509 .with_status(101)
510 .with_stderr(
511 "\
512 [UPDATING] `[..]` index
513 error: the lock file [CWD]/Cargo.lock needs to be updated but --locked was passed to prevent this
514 If you want to try to generate the lock file without accessing the network, \
515 remove the --locked flag and use --offline instead.
516 ",
517 )
518 .run();
519 }
520
521 #[cargo_test]
v2_format_preserved()522 fn v2_format_preserved() {
523 let cksum = Package::new("bar", "0.1.0").publish();
524
525 let lockfile = format!(
526 r#"# This file is automatically @generated by Cargo.
527 # It is not intended for manual editing.
528 [[package]]
529 name = "bar"
530 version = "0.1.0"
531 source = "registry+https://github.com/rust-lang/crates.io-index"
532 checksum = "{}"
533
534 [[package]]
535 name = "foo"
536 version = "0.0.1"
537 dependencies = [
538 "bar",
539 ]
540 "#,
541 cksum
542 );
543
544 let p = project()
545 .file(
546 "Cargo.toml",
547 r#"
548 [project]
549 name = "foo"
550 version = "0.0.1"
551 authors = []
552
553 [dependencies]
554 bar = "0.1.0"
555 "#,
556 )
557 .file("src/lib.rs", "")
558 .file("Cargo.lock", &lockfile)
559 .build();
560
561 p.cargo("fetch").run();
562
563 let lock = p.read_lockfile();
564 assert_match_exact(&lockfile, &lock);
565 }
566
567 #[cargo_test]
v2_path_and_crates_io()568 fn v2_path_and_crates_io() {
569 let cksum010 = Package::new("a", "0.1.0").publish();
570 let cksum020 = Package::new("a", "0.2.0").publish();
571
572 let lockfile = format!(
573 r#"# This file is automatically @generated by Cargo.
574 # It is not intended for manual editing.
575 [[package]]
576 name = "a"
577 version = "0.1.0"
578 source = "registry+https://github.com/rust-lang/crates.io-index"
579 checksum = "{}"
580
581 [[package]]
582 name = "a"
583 version = "0.2.0"
584
585 [[package]]
586 name = "a"
587 version = "0.2.0"
588 source = "registry+https://github.com/rust-lang/crates.io-index"
589 checksum = "{}"
590
591 [[package]]
592 name = "foo"
593 version = "0.0.1"
594 dependencies = [
595 "a 0.1.0",
596 "a 0.2.0",
597 "a 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
598 ]
599 "#,
600 cksum010, cksum020,
601 );
602
603 let p = project()
604 .file(
605 "Cargo.toml",
606 r#"
607 [project]
608 name = "foo"
609 version = "0.0.1"
610 authors = []
611
612 [dependencies]
613 a = { path = 'a' }
614 b = { version = "0.1", package = 'a' }
615 c = { version = "0.2", package = 'a' }
616 "#,
617 )
618 .file("src/lib.rs", "")
619 .file(
620 "a/Cargo.toml",
621 r#"
622 [project]
623 name = "a"
624 version = "0.2.0"
625 "#,
626 )
627 .file("a/src/lib.rs", "")
628 .file("Cargo.lock", &lockfile)
629 .build();
630
631 p.cargo("fetch").run();
632 p.cargo("fetch").run();
633
634 let lock = p.read_lockfile();
635 assert_match_exact(&lockfile, &lock);
636 }
637
638 #[cargo_test]
v3_and_git()639 fn v3_and_git() {
640 let (git_project, repo) = git::new_repo("dep1", |project| {
641 project
642 .file("Cargo.toml", &basic_lib_manifest("dep1"))
643 .file("src/lib.rs", "")
644 });
645 let head_id = repo.head().unwrap().target().unwrap();
646
647 let lockfile = format!(
648 r#"# This file is automatically @generated by Cargo.
649 # It is not intended for manual editing.
650 version = 3
651
652 [[package]]
653 name = "dep1"
654 version = "0.5.0"
655 source = "git+{}?branch=master#{}"
656
657 [[package]]
658 name = "foo"
659 version = "0.0.1"
660 dependencies = [
661 "dep1",
662 ]
663 "#,
664 git_project.url(),
665 head_id,
666 );
667
668 let p = project()
669 .file(
670 "Cargo.toml",
671 &format!(
672 r#"
673 [project]
674 name = "foo"
675 version = "0.0.1"
676 authors = []
677
678 [dependencies]
679 dep1 = {{ git = '{}', branch = 'master' }}
680 "#,
681 git_project.url(),
682 ),
683 )
684 .file("src/lib.rs", "")
685 .file("Cargo.lock", "version = 3")
686 .build();
687
688 p.cargo("fetch").run();
689
690 let lock = p.read_lockfile();
691 assert_match_exact(&lockfile, &lock);
692 }
693
694 #[cargo_test]
lock_from_the_future()695 fn lock_from_the_future() {
696 let p = project()
697 .file(
698 "Cargo.toml",
699 r#"
700 [project]
701 name = "foo"
702 version = "0.0.1"
703 authors = []
704 "#,
705 )
706 .file("src/lib.rs", "")
707 .file("Cargo.lock", "version = 10000000")
708 .build();
709
710 p.cargo("fetch")
711 .with_stderr(
712 "\
713 error: failed to parse lock file at: [..]
714
715 Caused by:
716 lock file version `10000000` was found, but this version of Cargo does not \
717 understand this lock file, perhaps Cargo needs to be updated?
718 ",
719 )
720 .with_status(101)
721 .run();
722 }
723
724 #[cargo_test]
preserve_old_format_if_no_update_needed()725 fn preserve_old_format_if_no_update_needed() {
726 let cksum = Package::new("bar", "0.1.0").publish();
727 let lockfile = format!(
728 r#"# This file is automatically @generated by Cargo.
729 # It is not intended for manual editing.
730 [[package]]
731 name = "bar"
732 version = "0.1.0"
733 source = "registry+https://github.com/rust-lang/crates.io-index"
734
735 [[package]]
736 name = "foo"
737 version = "0.0.1"
738 dependencies = [
739 "bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
740 ]
741
742 [metadata]
743 "checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}"
744 "#,
745 cksum
746 );
747
748 let p = project()
749 .file(
750 "Cargo.toml",
751 r#"
752 [project]
753 name = "foo"
754 version = "0.0.1"
755 authors = []
756
757 [dependencies]
758 bar = "0.1.0"
759 "#,
760 )
761 .file("src/lib.rs", "")
762 .file("Cargo.lock", &lockfile)
763 .build();
764
765 p.cargo("build --locked").run();
766 }
767
768 #[cargo_test]
same_name_version_different_sources()769 fn same_name_version_different_sources() {
770 let cksum = Package::new("foo", "0.1.0").publish();
771 let (git_project, repo) = git::new_repo("dep1", |project| {
772 project
773 .file(
774 "Cargo.toml",
775 r#"
776 [project]
777 name = "foo"
778 version = "0.1.0"
779 "#,
780 )
781 .file("src/lib.rs", "")
782 });
783 let head_id = repo.head().unwrap().target().unwrap();
784
785 // Lockfile was generated with Rust 1.51
786 let lockfile = format!(
787 r#"# This file is automatically @generated by Cargo.
788 # It is not intended for manual editing.
789 version = 3
790
791 [[package]]
792 name = "foo"
793 version = "0.1.0"
794 dependencies = [
795 "foo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
796 "foo 0.1.0 (git+{url})",
797 ]
798
799 [[package]]
800 name = "foo"
801 version = "0.1.0"
802 source = "registry+https://github.com/rust-lang/crates.io-index"
803 checksum = "{cksum}"
804
805 [[package]]
806 name = "foo"
807 version = "0.1.0"
808 source = "git+{url}#{sha}"
809 "#,
810 sha = head_id,
811 url = git_project.url(),
812 cksum = cksum
813 );
814
815 let p = project()
816 .file(
817 "Cargo.toml",
818 &format!(
819 r#"
820 [project]
821 name = "foo"
822 version = "0.1.0"
823
824 [dependencies]
825 foo = "0.1.0"
826 foo2 = {{ git = '{}', package = 'foo' }}
827 "#,
828 git_project.url(),
829 ),
830 )
831 .file("src/lib.rs", "")
832 .file("Cargo.lock", &lockfile)
833 .build();
834
835 p.cargo("build").run();
836
837 assert_eq!(p.read_file("Cargo.lock"), lockfile);
838 }
839