@@ -4029,3 +4029,327 @@ fn mergeable_info_dep_collision() {
40294029 // ...and the fingerprint content are different (path to dep.json different)
40304030 assert_ne ! ( first_fingerprint, second_fingerprint) ;
40314031}
4032+
4033+ #[ cargo_test( nightly, reason = "public-dependency feature is unstable" ) ]
4034+ fn doc_with_public_dependency_transitive ( ) {
4035+ // selected is the user-chosen package
4036+ // foo-dep is a direct dep of selected
4037+ // public-bar-dep is a public dep of foo-dep
4038+ // public-baz-dep is a public dep of public-bar-dep
4039+ // All four should be documented since the whole chain is public.
4040+
4041+ Package :: new ( "public-baz-dep" , "0.0.1" )
4042+ . file ( "src/lib.rs" , "pub fn public_baz_dep() {}" )
4043+ . publish ( ) ;
4044+
4045+ Package :: new ( "public-bar-dep" , "0.0.1" )
4046+ . cargo_feature ( "public-dependency" )
4047+ . add_dep (
4048+ cargo_test_support:: registry:: Dependency :: new ( "public-baz-dep" , "0.0.1" ) . public ( true ) ,
4049+ )
4050+ . file ( "src/lib.rs" , "pub fn public_bar_dep() {}" )
4051+ . publish ( ) ;
4052+
4053+ Package :: new ( "foo-dep" , "0.0.1" )
4054+ . cargo_feature ( "public-dependency" )
4055+ . add_dep (
4056+ cargo_test_support:: registry:: Dependency :: new ( "public-bar-dep" , "0.0.1" ) . public ( true ) ,
4057+ )
4058+ . file ( "src/lib.rs" , "pub fn foo_dep() {}" )
4059+ . publish ( ) ;
4060+
4061+ let p = project ( )
4062+ . file (
4063+ "Cargo.toml" ,
4064+ r#"
4065+ cargo-features = ["public-dependency"]
4066+
4067+ [package]
4068+ name = "selected"
4069+ version = "0.0.1"
4070+ edition = "2021"
4071+
4072+ [dependencies]
4073+ foo-dep = "0.0.1"
4074+ "# ,
4075+ )
4076+ . file ( "src/lib.rs" , "pub fn selected() {}" )
4077+ . build ( ) ;
4078+
4079+ p. cargo ( "doc -Zpublic-dependency" )
4080+ . masquerade_as_nightly_cargo ( & [ "public-dependency" ] )
4081+ . with_stderr_data (
4082+ str![ [ r#"
4083+ [UPDATING] `dummy-registry` index
4084+ [LOCKING] 3 packages to latest compatible versions
4085+ [DOWNLOADING] crates ...
4086+ [DOWNLOADED] public-baz-dep v0.0.1 (registry `dummy-registry`)
4087+ [DOWNLOADED] public-bar-dep v0.0.1 (registry `dummy-registry`)
4088+ [DOWNLOADED] foo-dep v0.0.1 (registry `dummy-registry`)
4089+ [DOCUMENTING] public-baz-dep v0.0.1
4090+ [CHECKING] public-baz-dep v0.0.1
4091+ [DOCUMENTING] public-bar-dep v0.0.1
4092+ [CHECKING] public-bar-dep v0.0.1
4093+ [DOCUMENTING] foo-dep v0.0.1
4094+ [CHECKING] foo-dep v0.0.1
4095+ [DOCUMENTING] selected v0.0.1 ([ROOT]/foo)
4096+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
4097+ [GENERATED] [ROOT]/foo/target/doc/selected/index.html
4098+
4099+ "# ] ]
4100+ . unordered ( ) ,
4101+ )
4102+ . run ( ) ;
4103+
4104+ // All four are documented: the whole chain is public.
4105+ assert ! ( p. root( ) . join( "target/doc/selected/index.html" ) . is_file( ) ) ;
4106+ assert ! ( p. root( ) . join( "target/doc/foo_dep/index.html" ) . is_file( ) ) ;
4107+ assert ! (
4108+ p. root( )
4109+ . join( "target/doc/public_bar_dep/index.html" )
4110+ . is_file( )
4111+ ) ;
4112+ assert ! (
4113+ p. root( )
4114+ . join( "target/doc/public_baz_dep/index.html" )
4115+ . is_file( )
4116+ ) ;
4117+ }
4118+
4119+ #[ cargo_test( nightly, reason = "public-dependency feature is unstable" ) ]
4120+ fn doc_direct_deps_always_documented ( ) {
4121+ // Direct dependencies should always be documented regardless of public flag
4122+ // foo -> bar (public=true), baz (public=false)
4123+ // Both bar and baz should be documented since they are direct deps
4124+
4125+ Package :: new ( "bar" , "0.0.1" )
4126+ . file ( "src/lib.rs" , "pub fn bar() {}" )
4127+ . publish ( ) ;
4128+
4129+ Package :: new ( "baz" , "0.0.1" )
4130+ . file ( "src/lib.rs" , "pub fn baz() {}" )
4131+ . publish ( ) ;
4132+
4133+ let p = project ( )
4134+ . file (
4135+ "Cargo.toml" ,
4136+ r#"
4137+ cargo-features = ["public-dependency"]
4138+
4139+ [package]
4140+ name = "foo"
4141+ version = "0.0.1"
4142+ edition = "2021"
4143+
4144+ [dependencies]
4145+ bar = { version = "0.0.1", public = true }
4146+ baz = { version = "0.0.1", public = false }
4147+ "# ,
4148+ )
4149+ . file ( "src/lib.rs" , "pub fn foo() {}" )
4150+ . build ( ) ;
4151+
4152+ p. cargo ( "doc -Zpublic-dependency" )
4153+ . masquerade_as_nightly_cargo ( & [ "public-dependency" ] )
4154+ . with_stderr_data (
4155+ str![ [ r#"
4156+ [UPDATING] `dummy-registry` index
4157+ [LOCKING] 2 packages to latest compatible versions
4158+ [DOWNLOADING] crates ...
4159+ [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`)
4160+ [DOWNLOADED] baz v0.0.1 (registry `dummy-registry`)
4161+ [DOCUMENTING] bar v0.0.1
4162+ [CHECKING] bar v0.0.1
4163+ [DOCUMENTING] baz v0.0.1
4164+ [CHECKING] baz v0.0.1
4165+ [DOCUMENTING] foo v0.0.1 ([ROOT]/foo)
4166+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
4167+ [GENERATED] [ROOT]/foo/target/doc/foo/index.html
4168+
4169+ "# ] ]
4170+ . unordered ( ) ,
4171+ )
4172+ . run ( ) ;
4173+
4174+ // Both direct deps should be documented
4175+ assert ! ( p. root( ) . join( "target/doc/foo/index.html" ) . is_file( ) ) ;
4176+ assert ! ( p. root( ) . join( "target/doc/bar/index.html" ) . is_file( ) ) ;
4177+ assert ! ( p. root( ) . join( "target/doc/baz/index.html" ) . is_file( ) ) ;
4178+ }
4179+
4180+ #[ cargo_test( nightly, reason = "public-dependency feature is unstable" ) ]
4181+ fn doc_with_private_dependency ( ) {
4182+ // foo -> bar (direct dep) -> baz (transitive private dep of bar)
4183+
4184+ Package :: new ( "baz" , "0.0.1" )
4185+ . file ( "src/lib.rs" , "pub fn baz() {}" )
4186+ . publish ( ) ;
4187+
4188+ Package :: new ( "bar" , "0.0.1" )
4189+ . cargo_feature ( "public-dependency" )
4190+ . add_dep ( cargo_test_support:: registry:: Dependency :: new ( "baz" , "0.0.1" ) . public ( false ) )
4191+ . file ( "src/lib.rs" , "pub fn bar() {}" )
4192+ . publish ( ) ;
4193+
4194+ let p = project ( )
4195+ . file (
4196+ "Cargo.toml" ,
4197+ r#"
4198+ cargo-features = ["public-dependency"]
4199+
4200+ [package]
4201+ name = "foo"
4202+ version = "0.0.1"
4203+ edition = "2021"
4204+
4205+ [dependencies]
4206+ bar = "0.0.1"
4207+ "# ,
4208+ )
4209+ . file ( "src/lib.rs" , "pub fn foo() {}" )
4210+ . build ( ) ;
4211+
4212+ p. cargo ( "doc -Zpublic-dependency" )
4213+ . masquerade_as_nightly_cargo ( & [ "public-dependency" ] )
4214+ . with_stderr_data (
4215+ str![ [ r#"
4216+ [UPDATING] `dummy-registry` index
4217+ [LOCKING] 2 packages to latest compatible versions
4218+ [DOWNLOADING] crates ...
4219+ [DOWNLOADED] baz v0.0.1 (registry `dummy-registry`)
4220+ [DOWNLOADED] bar v0.0.1 (registry `dummy-registry`)
4221+ [DOCUMENTING] baz v0.0.1
4222+ [CHECKING] baz v0.0.1
4223+ [DOCUMENTING] bar v0.0.1
4224+ [CHECKING] bar v0.0.1
4225+ [DOCUMENTING] foo v0.0.1 ([ROOT]/foo)
4226+ [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
4227+ [GENERATED] [ROOT]/foo/target/doc/foo/index.html
4228+
4229+ "# ] ]
4230+ . unordered ( ) ,
4231+ )
4232+ . run ( ) ;
4233+
4234+ assert ! ( p. root( ) . join( "target/doc/foo/index.html" ) . is_file( ) ) ;
4235+ assert ! ( p. root( ) . join( "target/doc/bar/index.html" ) . is_file( ) ) ;
4236+ assert ! ( p. root( ) . join( "target/doc/baz/index.html" ) . is_file( ) ) ;
4237+ }
4238+
4239+ #[ cargo_test( nightly, reason = "public-dependency feature is unstable" ) ]
4240+ fn doc_mixed_public_private_deps ( ) {
4241+ // foo -> pub_dep (public), priv_dep (private), priv_dep_with_dep (unannotated)
4242+ // priv_dep_with_dep -> transitive
4243+
4244+ Package :: new ( "pub_dep" , "0.0.1" )
4245+ . file ( "src/lib.rs" , "pub fn pub_dep() {}" )
4246+ . publish ( ) ;
4247+
4248+ Package :: new ( "priv_dep" , "0.0.1" )
4249+ . file ( "src/lib.rs" , "pub fn priv_dep() {}" )
4250+ . publish ( ) ;
4251+
4252+ Package :: new ( "transitive" , "0.0.1" )
4253+ . file ( "src/lib.rs" , "pub fn transitive() {}" )
4254+ . publish ( ) ;
4255+
4256+ Package :: new ( "priv_dep_with_dep" , "0.0.1" )
4257+ . dep ( "transitive" , "0.0.1" )
4258+ . file ( "src/lib.rs" , "pub fn priv_dep_with_dep() {}" )
4259+ . publish ( ) ;
4260+
4261+ let p = project ( )
4262+ . file (
4263+ "Cargo.toml" ,
4264+ r#"
4265+ cargo-features = ["public-dependency"]
4266+
4267+ [package]
4268+ name = "foo"
4269+ version = "0.0.1"
4270+ edition = "2021"
4271+
4272+ [dependencies]
4273+ pub_dep = { version = "0.0.1", public = true }
4274+ priv_dep = { version = "0.0.1", public = false }
4275+ priv_dep_with_dep = "0.0.1"
4276+ "# ,
4277+ )
4278+ . file ( "src/lib.rs" , "pub fn foo() {}" )
4279+ . build ( ) ;
4280+
4281+ p. cargo ( "doc -Zpublic-dependency" )
4282+ . masquerade_as_nightly_cargo ( & [ "public-dependency" ] )
4283+ . run ( ) ;
4284+
4285+ assert ! ( p. root( ) . join( "target/doc/foo/index.html" ) . is_file( ) ) ;
4286+ assert ! ( p. root( ) . join( "target/doc/pub_dep/index.html" ) . is_file( ) ) ;
4287+ assert ! ( p. root( ) . join( "target/doc/priv_dep/index.html" ) . is_file( ) ) ;
4288+ assert ! (
4289+ p. root( )
4290+ . join( "target/doc/priv_dep_with_dep/index.html" )
4291+ . is_file( )
4292+ ) ;
4293+ assert ! ( p. root( ) . join( "target/doc/transitive/index.html" ) . is_file( ) ) ;
4294+ }
4295+
4296+ #[ cargo_test( nightly, reason = "public-dependency feature is unstable" ) ]
4297+ fn doc_workspace_member_private_dep ( ) {
4298+ // selected and skipped are both workspace members.
4299+ // selected has a private dep on skipped.
4300+ // skipped has a dep on transitive (a registry crate).
4301+ // Running `cargo doc -p selected` currently documents all of them,
4302+ // including transitive, because the public-dependency filter is not
4303+ // applied to workspace members' deps.
4304+
4305+ Package :: new ( "transitive" , "0.0.1" )
4306+ . file ( "src/lib.rs" , "pub fn transitive() {}" )
4307+ . publish ( ) ;
4308+
4309+ let p = project ( )
4310+ . file (
4311+ "Cargo.toml" ,
4312+ r#"
4313+ [workspace]
4314+ members = ["selected", "skipped"]
4315+ "# ,
4316+ )
4317+ . file (
4318+ "selected/Cargo.toml" ,
4319+ r#"
4320+ cargo-features = ["public-dependency"]
4321+
4322+ [package]
4323+ name = "selected"
4324+ version = "0.0.1"
4325+ edition = "2021"
4326+
4327+ [dependencies]
4328+ skipped = { path = "../skipped", public = false }
4329+ "# ,
4330+ )
4331+ . file ( "selected/src/lib.rs" , "pub fn selected() {}" )
4332+ . file (
4333+ "skipped/Cargo.toml" ,
4334+ r#"
4335+ [package]
4336+ name = "skipped"
4337+ version = "0.0.1"
4338+ edition = "2021"
4339+
4340+ [dependencies]
4341+ transitive = "0.0.1"
4342+ "# ,
4343+ )
4344+ . file ( "skipped/src/lib.rs" , "pub fn skipped() {}" )
4345+ . build ( ) ;
4346+
4347+ p. cargo ( "doc -p selected -Zpublic-dependency" )
4348+ . masquerade_as_nightly_cargo ( & [ "public-dependency" ] )
4349+ . run ( ) ;
4350+
4351+ assert ! ( p. root( ) . join( "target/doc/selected/index.html" ) . is_file( ) ) ;
4352+ assert ! ( p. root( ) . join( "target/doc/skipped/index.html" ) . is_file( ) ) ;
4353+ // transitive is documented under the current behavior (no filter applied)
4354+ assert ! ( p. root( ) . join( "target/doc/transitive/index.html" ) . is_file( ) ) ;
4355+ }
0 commit comments