@@ -7,7 +7,7 @@ use assert_cmd::cargo::cargo_bin_cmd;
77use dylint_internal:: {
88 CommandExt ,
99 clippy_utils:: { set_clippy_utils_dependency_revision, set_toolchain_channel} ,
10- env,
10+ env, library_filename_with_toolchain ,
1111 link:: { debug_path_with_active_toolchain, debug_path_with_toolchain} ,
1212 msrv,
1313 rustup:: { SanitizeEnvironment , active_toolchain} ,
@@ -16,10 +16,60 @@ use dylint_internal::{
1616use predicates:: prelude:: * ;
1717use std:: {
1818 env:: join_paths,
19+ fmt:: Write as _,
20+ fs:: OpenOptions ,
21+ io:: Write ,
1922 path:: { Path , PathBuf } ,
2023} ;
2124use tempfile:: tempdir;
2225
26+ #[ test]
27+ fn metadata_and_lib_path_are_deduplicated ( ) {
28+ let library_dir = tempdir ( ) . unwrap ( ) ;
29+ let manifest_dir = tempdir ( ) . unwrap ( ) ;
30+ #[ cfg( unix) ]
31+ let target_dir = tempdir ( ) . unwrap ( ) ;
32+
33+ new_template ( library_dir. path ( ) ) . unwrap ( ) ;
34+ let toolchain = active_toolchain ( library_dir. path ( ) ) . unwrap ( ) ;
35+
36+ dylint_internal:: cargo:: init ( "package `metadata_and_lib_path_test`" )
37+ . build ( )
38+ . current_dir ( & manifest_dir)
39+ . args ( [ "--name" , "metadata_and_lib_path_test" ] )
40+ . success ( )
41+ . unwrap ( ) ;
42+
43+ let library_dir_path = dunce:: canonicalize ( & library_dir) . unwrap ( ) ;
44+ append_workspace_metadata ( manifest_dir. path ( ) , [ library_dir_path. as_path ( ) ] ) . unwrap ( ) ;
45+
46+ // On Unix, the symlink makes canonicalization change the library path. Windows symlinks or
47+ // junctions can cause the same mismatch. This test does not create an alias on Windows,
48+ // where symlink creation can require additional privileges. The Windows case checks
49+ // deduplication without exercising alias resolution.
50+ #[ cfg( unix) ]
51+ std:: os:: unix:: fs:: symlink ( & target_dir, manifest_dir. path ( ) . join ( "target" ) ) . unwrap ( ) ;
52+
53+ cargo_bin_cmd ! ( "cargo-dylint" )
54+ . current_dir ( & manifest_dir)
55+ . args ( [ "dylint" , "list" , "--all" ] )
56+ . assert ( )
57+ . success ( ) ;
58+
59+ let library_path = target_libraries_directory ( manifest_dir. path ( ) , & toolchain)
60+ . unwrap ( )
61+ . join ( library_filename_with_toolchain ( "fill_me_in" , & toolchain) ) ;
62+
63+ cargo_bin_cmd ! ( "cargo-dylint" )
64+ . current_dir ( & manifest_dir)
65+ . args ( [ "dylint" , "list" , "--all" , "--no-build" , "--lib-path" ] )
66+ . arg ( & library_path)
67+ . assert ( )
68+ . success ( )
69+ // One occurrence in the library heading and one in its lint listing.
70+ . stdout ( predicate:: str:: contains ( "fill_me_in" ) . count ( 2 ) ) ;
71+ }
72+
2373#[ test]
2474fn one_name_multiple_toolchains ( ) {
2575 let tempdir = tempdir ( ) . unwrap ( ) ;
@@ -227,6 +277,40 @@ fn relative_path() {
227277 }
228278}
229279
280+ fn append_workspace_metadata < ' a > (
281+ manifest_dir : & Path ,
282+ lib_dirs : impl IntoIterator < Item = & ' a Path > ,
283+ ) -> Result < ( ) > {
284+ let manifest = manifest_dir. join ( "Cargo.toml" ) ;
285+ let mut file = OpenOptions :: new ( )
286+ . append ( true )
287+ . open ( & manifest)
288+ . with_context ( || format ! ( "Could not open `{}`" , manifest. to_string_lossy( ) ) ) ?;
289+
290+ writeln ! ( file, "{}" , workspace_metadata( lib_dirs) )
291+ . with_context ( || format ! ( "Could not write to `{}`" , manifest. to_string_lossy( ) ) ) ?;
292+
293+ Ok ( ( ) )
294+ }
295+
296+ fn workspace_metadata < ' a > ( lib_dirs : impl IntoIterator < Item = & ' a Path > ) -> String {
297+ let mut metadata = String :: from (
298+ r"
299+ [workspace.metadata.dylint]
300+ libraries = [
301+ " ,
302+ ) ;
303+ for lib_dir in lib_dirs {
304+ let path = toml:: Value :: String ( lib_dir. to_string_lossy ( ) . into_owned ( ) ) ;
305+ writeln ! ( & mut metadata, " {{ path = {path} }}," ) . unwrap ( ) ;
306+ }
307+ metadata. push_str (
308+ r"]
309+ " ,
310+ ) ;
311+ metadata
312+ }
313+
230314// smoelius: This test checks that if a library path is passed to `--path`, a "No library packages
231315// found in ..." message is emitted.
232316#[ test]
@@ -260,3 +344,18 @@ fn target_debug(dir: &Path) -> Result<PathBuf> {
260344 let debug_dir = metadata. target_directory . join ( "debug" ) ;
261345 dunce:: canonicalize ( & debug_dir) . with_context ( || format ! ( "Could not canonicalize `{debug_dir}`" ) )
262346}
347+
348+ // smoelius: Hack. This function duplicates logic from, e.g.,
349+ // `dylint::library_packages::Package::library_path_with_toolchain`.
350+ fn target_libraries_directory ( dir : & Path , toolchain : & str ) -> Result < PathBuf > {
351+ let target_directory = target_directory ( dir) ?;
352+ Ok ( target_directory
353+ . join ( "dylint/libraries" )
354+ . join ( toolchain)
355+ . join ( "release" ) )
356+ }
357+
358+ fn target_directory ( dir : & Path ) -> Result < PathBuf > {
359+ let metadata = dylint_internal:: cargo:: metadata ( dir) ?;
360+ Ok ( metadata. target_directory . into_std_path_buf ( ) )
361+ }
0 commit comments