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