@@ -123,6 +123,94 @@ fn deferred() {
123123 . run ( ) ;
124124}
125125
126+ #[ cargo_test]
127+ fn deferred_v5 ( ) {
128+ // A modified version of the deferred test from above to enable
129+ // an entire dependency in a deferred way.
130+ Package :: new ( "bar" , "1.0.0" )
131+ . feature ( "feat" , & [ "feat_dep" ] )
132+ . add_dep ( Dependency :: new ( "feat_dep" , "1.0" ) . optional ( true ) )
133+ . file ( "src/lib.rs" , "extern crate feat_dep;" )
134+ . publish ( ) ;
135+ Package :: new ( "dep" , "1.0.0" )
136+ . add_dep ( Dependency :: new ( "bar" , "1.0" ) . optional ( true ) )
137+ . feature ( "feat" , & [ "bar?/feat" ] )
138+ . publish ( ) ;
139+ Package :: new ( "bar_activator" , "1.0.0" )
140+ . feature_dep ( "dep" , "1.0" , & [ "bar" ] )
141+ . publish ( ) ;
142+ Package :: new ( "feat_dep" , "1.0.0" ) . publish ( ) ;
143+ let p = project ( )
144+ . file (
145+ "Cargo.toml" ,
146+ r#"
147+ [package]
148+ name = "foo"
149+ version = "0.1.0"
150+ edition = "2015"
151+
152+ [dependencies]
153+ dep = { version = "1.0", features = ["feat"] }
154+ bar_activator = "1.0"
155+ "# ,
156+ )
157+ . file ( "src/lib.rs" , "" )
158+ . build ( ) ;
159+
160+ p. cargo ( "check" )
161+ . with_stderr_data ( str![ [ r#"
162+ [UPDATING] `dummy-registry` index
163+ [LOCKING] 4 packages to latest compatible versions
164+ [DOWNLOADING] crates ...
165+ [DOWNLOADED] feat_dep v1.0.0 (registry `dummy-registry`)
166+ [DOWNLOADED] dep v1.0.0 (registry `dummy-registry`)
167+ [DOWNLOADED] bar_activator v1.0.0 (registry `dummy-registry`)
168+ [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
169+ [CHECKING] feat_dep v1.0.0
170+ [CHECKING] bar v1.0.0
171+ [CHECKING] dep v1.0.0
172+ [CHECKING] bar_activator v1.0.0
173+ [CHECKING] foo v0.1.0 ([ROOT]/foo)
174+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
175+
176+ "# ] ] )
177+ . run ( ) ;
178+ let lockfile = p. read_lockfile ( ) ;
179+
180+ assert ! (
181+ lockfile. contains( r#"version = 4"# ) ,
182+ "lockfile version is not 4!\n {lockfile}" ,
183+ ) ;
184+ // Previous behavior: feat_dep is inside lockfile.
185+ assert ! (
186+ lockfile. contains( r#"name = "feat_dep""# ) ,
187+ "feat_dep not found\n {lockfile}" ,
188+ ) ;
189+ // Update to new lockfile version
190+ let new_lockfile = lockfile. replace ( "version = 4" , "version = 5" ) ;
191+ p. change_file ( "Cargo.lock" , & new_lockfile) ;
192+
193+ // We should still compile feat_dep
194+ p. cargo ( "check -Znext-lockfile-bump" )
195+ . masquerade_as_nightly_cargo ( & [ "weak_namespaced_check" ] )
196+ . with_stderr_data ( str![ [ r#"
197+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
198+
199+ "# ] ] )
200+ . run ( ) ;
201+
202+ let lockfile = p. read_lockfile ( ) ;
203+ assert ! (
204+ lockfile. contains( r#"version = 5"# ) ,
205+ "lockfile version is not 5!\n {lockfile}" ,
206+ ) ;
207+ // New behavior: feat_dep is still there.
208+ assert ! (
209+ lockfile. contains( r#"name = "feat_dep""# ) ,
210+ "feat_dep not found\n {lockfile}" ,
211+ ) ;
212+ }
213+
126214#[ cargo_test]
127215fn not_optional_dep ( ) {
128216 // Attempt to use dep_name?/feat where dep_name is not optional.
@@ -446,6 +534,85 @@ foo v0.1.0 ([ROOT]/foo) feats:f1,f2
446534 . run ( ) ;
447535}
448536
537+ #[ cargo_test]
538+ fn weak_namespaced_v5 ( ) {
539+ // Behavior with a dep: dependency.
540+ Package :: new ( "maybe_enabled" , "1.0.0" )
541+ . feature ( "feat" , & [ ] )
542+ . file ( "src/lib.rs" , & require ( & [ "feat" ] , & [ ] ) )
543+ . publish ( ) ;
544+ Package :: new ( "bar" , "1.0.0" )
545+ . add_dep ( Dependency :: new ( "maybe_enabled" , "1.0" ) . optional ( true ) )
546+ . feature ( "f1" , & [ "maybe_enabled?/feat" ] )
547+ . feature ( "f2" , & [ "dep:maybe_enabled" ] )
548+ . publish ( ) ;
549+ let p = project ( )
550+ . file (
551+ "Cargo.toml" ,
552+ r#"
553+ [package]
554+ name = "foo"
555+ version = "0.1.0"
556+ edition = "2015"
557+
558+ [dependencies]
559+ bar = { version = "1.0", features = ["f2", "f1"] }
560+ "# ,
561+ )
562+ . file ( "src/lib.rs" , "" )
563+ . build ( ) ;
564+
565+ p. cargo ( "check" )
566+ . with_stderr_data ( str![ [ r#"
567+ [UPDATING] `dummy-registry` index
568+ [LOCKING] 2 packages to latest compatible versions
569+ [DOWNLOADING] crates ...
570+ [DOWNLOADED] maybe_enabled v1.0.0 (registry `dummy-registry`)
571+ [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
572+ [CHECKING] maybe_enabled v1.0.0
573+ [CHECKING] bar v1.0.0
574+ [CHECKING] foo v0.1.0 ([ROOT]/foo)
575+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
576+
577+ "# ] ] )
578+ . run ( ) ;
579+
580+ let lockfile = p. read_lockfile ( ) ;
581+
582+ assert ! (
583+ lockfile. contains( r#"version = 4"# ) ,
584+ "lockfile version is not 4!\n {lockfile}" ,
585+ ) ;
586+ // Previous behavior: maybe_enabled is inside lockfile.
587+ assert ! (
588+ lockfile. contains( r#"name = "maybe_enabled""# ) ,
589+ "maybe_enabled not found\n {lockfile}" ,
590+ ) ;
591+ // Update to new lockfile version
592+ let new_lockfile = lockfile. replace ( "version = 4" , "version = 5" ) ;
593+ p. change_file ( "Cargo.lock" , & new_lockfile) ;
594+
595+ // We should still compile maybe_enabled
596+ p. cargo ( "check -Znext-lockfile-bump" )
597+ . masquerade_as_nightly_cargo ( & [ "weak_namespaced_check" ] )
598+ . with_stderr_data ( str![ [ r#"
599+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
600+
601+ "# ] ] )
602+ . run ( ) ;
603+
604+ let lockfile = p. read_lockfile ( ) ;
605+ assert ! (
606+ lockfile. contains( r#"version = 5"# ) ,
607+ "lockfile version is not 5!\n {lockfile}" ,
608+ ) ;
609+ // New behavior: maybe_enabled is still there.
610+ assert ! (
611+ lockfile. contains( r#"name = "maybe_enabled""# ) ,
612+ "maybe_enabled not found\n {lockfile}" ,
613+ ) ;
614+ }
615+
449616#[ cargo_test]
450617fn tree ( ) {
451618 Package :: new ( "bar" , "1.0.0" )
@@ -666,3 +833,181 @@ optional = true
666833 ) ] ,
667834 ) ;
668835}
836+
837+ #[ cargo_test]
838+ fn disabled_weak_direct_dep ( ) {
839+ // Issue #10801
840+ // A weak direct dependency should be included in Cargo.lock,
841+ // even if disabled, and even if on lockfile version 5.
842+ Package :: new ( "bar" , "1.0.0" )
843+ . feature ( "feat" , & [ ] )
844+ . file ( "src/lib.rs" , & require ( & [ "feat" ] , & [ ] ) )
845+ . publish ( ) ;
846+ let p = project ( )
847+ . file (
848+ "Cargo.toml" ,
849+ r#"
850+ [package]
851+ name = "foo"
852+ version = "0.1.0"
853+ edition = "2015"
854+
855+ [dependencies]
856+ bar = { version = "1.0", optional = true }
857+
858+ [features]
859+ f1 = ["bar?/feat"]
860+ "# ,
861+ )
862+ . file ( "src/lib.rs" , & require ( & [ "f1" ] , & [ ] ) )
863+ . build ( ) ;
864+
865+ p. cargo ( "generate-lockfile" ) . run ( ) ;
866+
867+ let lockfile = p. read_lockfile ( ) ;
868+ assert ! (
869+ lockfile. contains( r#"version = 4"# ) ,
870+ "lockfile version is not 4!\n {lockfile}" ,
871+ ) ;
872+ // Previous behavior: bar is inside lockfile.
873+ assert ! (
874+ lockfile. contains( r#"name = "bar""# ) ,
875+ "bar not found\n {lockfile}" ,
876+ ) ;
877+
878+ // Update to new lockfile version
879+ let new_lockfile = lockfile. replace ( "version = 4" , "version = 5" ) ;
880+ p. change_file ( "Cargo.lock" , & new_lockfile) ;
881+
882+ p. cargo ( "check -Znext-lockfile-bump --features f1" )
883+ . masquerade_as_nightly_cargo ( & [ "weak_namespaced_check" ] )
884+ . with_stderr_data ( str![ [ r#"
885+ [DOWNLOADING] crates ...
886+ [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
887+ [CHECKING] foo v0.1.0 ([ROOT]/foo)
888+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
889+
890+ "# ] ] )
891+ . run ( ) ;
892+
893+ let lockfile = p. read_lockfile ( ) ;
894+ assert ! (
895+ lockfile. contains( r#"version = 5"# ) ,
896+ "lockfile version is not 5!\n {lockfile}" ,
897+ ) ;
898+ // New behavior: bar is still there because it is a direct (optional) dependency.
899+ assert ! (
900+ lockfile. contains( r#"name = "bar""# ) ,
901+ "bar not found\n {lockfile}" ,
902+ ) ;
903+
904+ p. cargo ( "check -Znext-lockfile-bump --features f1,bar" )
905+ . masquerade_as_nightly_cargo ( & [ "weak_namespaced_check" ] )
906+ . with_stderr_data ( str![ [ r#"
907+ [CHECKING] bar v1.0.0
908+ [CHECKING] foo v0.1.0 ([ROOT]/foo)
909+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
910+
911+ "# ] ] )
912+ . run ( ) ;
913+ }
914+
915+ #[ cargo_test]
916+ fn disabled_weak_optional_deps ( ) {
917+ // Issue #10801
918+ // A weak dependency of a dependency should not be included in Cargo.lock,
919+ // at least on lockfile version 5.
920+ Package :: new ( "bar" , "1.0.0" )
921+ . feature ( "feat" , & [ ] )
922+ . file ( "src/lib.rs" , & require ( & [ "feat" ] , & [ ] ) )
923+ . publish ( ) ;
924+ Package :: new ( "dep" , "1.0.0" )
925+ . add_dep ( Dependency :: new ( "bar" , "1.0" ) . optional ( true ) )
926+ . feature ( "feat" , & [ "bar?/feat" ] )
927+ . file ( "src/lib.rs" , "" )
928+ . publish ( ) ;
929+ let p = project ( )
930+ . file (
931+ "Cargo.toml" ,
932+ r#"
933+ [package]
934+ name = "foo"
935+ version = "0.1.0"
936+ edition = "2015"
937+
938+ [dependencies]
939+ dep = { version = "1.0", features = ["feat"] }
940+ "# ,
941+ )
942+ . file ( "src/lib.rs" , "" )
943+ . build ( ) ;
944+
945+ p. cargo ( "generate-lockfile" ) . run ( ) ;
946+
947+ let lockfile = p. read_lockfile ( ) ;
948+
949+ assert ! (
950+ lockfile. contains( r#"version = 4"# ) ,
951+ "lockfile version is not 4!\n {lockfile}" ,
952+ ) ;
953+ // Previous behavior: bar is inside lockfile.
954+ assert ! (
955+ lockfile. contains( r#"name = "bar""# ) ,
956+ "bar not found\n {lockfile}" ,
957+ ) ;
958+
959+ // Update to new lockfile version
960+ let new_lockfile = lockfile. replace ( "version = 4" , "version = 5" ) ;
961+ p. change_file ( "Cargo.lock" , & new_lockfile) ;
962+
963+ // Note how we are not downloading bar here
964+ p. cargo ( "check -Znext-lockfile-bump" )
965+ . masquerade_as_nightly_cargo ( & [ "weak_namespaced_check" ] )
966+ . with_stderr_data ( str![ [ r#"
967+ [DOWNLOADING] crates ...
968+ [DOWNLOADED] dep v1.0.0 (registry `dummy-registry`)
969+ [CHECKING] dep v1.0.0
970+ [CHECKING] foo v0.1.0 ([ROOT]/foo)
971+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
972+
973+ "# ] ] )
974+ . run ( ) ;
975+
976+ let lockfile = p. read_lockfile ( ) ;
977+ assert ! (
978+ lockfile. contains( r#"version = 5"# ) ,
979+ "lockfile version is not 5!\n {lockfile}" ,
980+ ) ;
981+ // New behavior: bar is gone.
982+ assert ! (
983+ !lockfile. contains( r#"name = "bar""# ) ,
984+ "bar inside lockfile!\n {lockfile}" ,
985+ ) ;
986+
987+ // Note how we are not downloading bar here
988+ p. cargo ( "check -Znext-lockfile-bump --features dep/bar" )
989+ . masquerade_as_nightly_cargo ( & [ "weak_namespaced_check" ] )
990+ . with_stderr_data ( str![ [ r#"
991+ [DOWNLOADING] crates ...
992+ [DOWNLOADED] bar v1.0.0 (registry `dummy-registry`)
993+ [CHECKING] bar v1.0.0
994+ [CHECKING] dep v1.0.0
995+ [CHECKING] foo v0.1.0 ([ROOT]/foo)
996+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
997+
998+ "# ] ] )
999+ . run ( ) ;
1000+
1001+ let lockfile = p. read_lockfile ( ) ;
1002+ assert ! (
1003+ lockfile. contains( r#"version = 5"# ) ,
1004+ "lockfile version is not 5!\n {lockfile}" ,
1005+ ) ;
1006+ // bar is still not there, even if dep/bar is enabled on the command line.
1007+ // This might be unintuitive, but it matches what happens on lock version 3
1008+ // if there was no optional feat = bar?/feat feature in bar.
1009+ assert ! (
1010+ !lockfile. contains( r#"name = "bar""# ) ,
1011+ "bar inside lockfile!\n {lockfile}" ,
1012+ ) ;
1013+ }
0 commit comments