| use stdx::trim_indent; |
| use test_fixture::WithFixture; |
| use test_utils::{assert_eq_text, CURSOR_MARKER}; |
| |
| use super::*; |
| |
| #[test] |
| fn trailing_comment_in_empty_file() { |
| check( |
| "foo::bar", |
| r#" |
| struct Struct; |
| // 0 = 1 |
| "#, |
| r#" |
| use foo::bar; |
| |
| struct Struct; |
| // 0 = 1 |
| "#, |
| ImportGranularity::Crate, |
| ); |
| } |
| |
| #[test] |
| fn respects_cfg_attr_fn() { |
| check( |
| r"bar::Bar", |
| r#" |
| #[cfg(test)] |
| fn foo() {$0} |
| "#, |
| r#" |
| #[cfg(test)] |
| fn foo() { |
| use bar::Bar; |
| } |
| "#, |
| ImportGranularity::Crate, |
| ); |
| } |
| |
| #[test] |
| fn respects_cfg_attr_const() { |
| check( |
| r"bar::Bar", |
| r#" |
| #[cfg(test)] |
| const FOO: Bar = {$0}; |
| "#, |
| r#" |
| #[cfg(test)] |
| const FOO: Bar = { |
| use bar::Bar; |
| }; |
| "#, |
| ImportGranularity::Crate, |
| ); |
| } |
| |
| #[test] |
| fn insert_skips_lone_glob_imports() { |
| check( |
| "use foo::baz::A", |
| r" |
| use foo::bar::*; |
| ", |
| r" |
| use foo::bar::*; |
| use foo::baz::A; |
| ", |
| ImportGranularity::Crate, |
| ); |
| } |
| |
| #[test] |
| fn insert_not_group() { |
| cov_mark::check!(insert_no_grouping_last); |
| check_with_config( |
| "use external_crate2::bar::A", |
| r" |
| use std::bar::B; |
| use external_crate::bar::A; |
| use crate::bar::A; |
| use self::bar::A; |
| use super::bar::A;", |
| r" |
| use std::bar::B; |
| use external_crate::bar::A; |
| use crate::bar::A; |
| use self::bar::A; |
| use super::bar::A; |
| use external_crate2::bar::A;", |
| &InsertUseConfig { |
| granularity: ImportGranularity::Item, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: false, |
| skip_glob_imports: true, |
| }, |
| ); |
| } |
| |
| #[test] |
| fn insert_existing() { |
| check_crate("std::fs", "use std::fs;", "use std::fs;") |
| } |
| |
| #[test] |
| fn insert_start() { |
| check_none( |
| "std::bar::AA", |
| r" |
| use std::bar::B; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::AA; |
| use std::bar::B; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| ) |
| } |
| |
| #[test] |
| fn insert_start_indent() { |
| check_none( |
| "std::bar::AA", |
| r" |
| use std::bar::B; |
| use std::bar::C;", |
| r" |
| use std::bar::AA; |
| use std::bar::B; |
| use std::bar::C;", |
| ); |
| check_none( |
| "std::bar::r#AA", |
| r" |
| use std::bar::B; |
| use std::bar::C;", |
| r" |
| use std::bar::r#AA; |
| use std::bar::B; |
| use std::bar::C;", |
| ); |
| } |
| |
| #[test] |
| fn insert_middle() { |
| cov_mark::check!(insert_group); |
| check_none( |
| "std::bar::EE", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::EE; |
| use std::bar::F; |
| use std::bar::G;", |
| ) |
| } |
| |
| #[test] |
| fn insert_middle_indent() { |
| check_none( |
| "std::bar::EE", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::EE; |
| use std::bar::F; |
| use std::bar::G;", |
| ); |
| check_none( |
| "std::bar::r#EE", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::r#EE; |
| use std::bar::F; |
| use std::bar::G;", |
| ); |
| } |
| |
| #[test] |
| fn insert_end() { |
| cov_mark::check!(insert_group_last); |
| check_none( |
| "std::bar::ZZ", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G; |
| use std::bar::ZZ;", |
| ) |
| } |
| |
| #[test] |
| fn insert_end_indent() { |
| check_none( |
| "std::bar::ZZ", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G; |
| use std::bar::ZZ;", |
| ); |
| check_none( |
| "std::bar::r#ZZ", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| use std::bar::F; |
| use std::bar::G; |
| use std::bar::r#ZZ;", |
| ); |
| } |
| |
| #[test] |
| fn insert_middle_nested() { |
| check_none( |
| "std::bar::EE", |
| r" |
| use std::bar::A; |
| use std::bar::{D, Z}; // example of weird imports due to user |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::EE; |
| use std::bar::{D, Z}; // example of weird imports due to user |
| use std::bar::F; |
| use std::bar::G;", |
| ); |
| check_none( |
| "std::bar::r#EE", |
| r" |
| use std::bar::A; |
| use std::bar::{D, Z}; // example of weird imports due to user |
| use std::bar::F; |
| use std::bar::G;", |
| r" |
| use std::bar::A; |
| use std::bar::r#EE; |
| use std::bar::{D, Z}; // example of weird imports due to user |
| use std::bar::F; |
| use std::bar::G;", |
| ); |
| } |
| |
| #[test] |
| fn insert_middle_groups() { |
| check_none( |
| "foo::bar::GG", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| |
| use foo::bar::F; |
| use foo::bar::H;", |
| r" |
| use std::bar::A; |
| use std::bar::D; |
| |
| use foo::bar::F; |
| use foo::bar::GG; |
| use foo::bar::H;", |
| ) |
| } |
| |
| #[test] |
| fn insert_first_matching_group() { |
| check_none( |
| "foo::bar::GG", |
| r" |
| use foo::bar::A; |
| use foo::bar::D; |
| |
| use std; |
| |
| use foo::bar::F; |
| use foo::bar::H;", |
| r" |
| use foo::bar::A; |
| use foo::bar::D; |
| use foo::bar::GG; |
| |
| use std; |
| |
| use foo::bar::F; |
| use foo::bar::H;", |
| ) |
| } |
| |
| #[test] |
| fn insert_missing_group_std() { |
| cov_mark::check!(insert_group_new_group); |
| check_none( |
| "std::fmt", |
| r" |
| use foo::bar::A; |
| use foo::bar::D;", |
| r" |
| use std::fmt; |
| |
| use foo::bar::A; |
| use foo::bar::D;", |
| ) |
| } |
| |
| #[test] |
| fn insert_missing_group_self() { |
| cov_mark::check!(insert_group_no_group); |
| check_none( |
| "self::fmt", |
| r" |
| use foo::bar::A; |
| use foo::bar::D;", |
| r" |
| use foo::bar::A; |
| use foo::bar::D; |
| |
| use self::fmt;", |
| ) |
| } |
| |
| #[test] |
| fn insert_no_imports() { |
| check_crate( |
| "foo::bar", |
| "fn main() {}", |
| r"use foo::bar; |
| |
| fn main() {}", |
| ) |
| } |
| |
| #[test] |
| fn insert_empty_file() { |
| cov_mark::check_count!(insert_empty_file, 2); |
| |
| // Default configuration |
| // empty files will get two trailing newlines |
| // this is due to the test case insert_no_imports above |
| check_crate( |
| "foo::bar", |
| "", |
| r"use foo::bar; |
| |
| ", |
| ); |
| |
| // "not group" configuration |
| check_with_config( |
| "use external_crate2::bar::A", |
| r"", |
| r"use external_crate2::bar::A; |
| |
| ", |
| &InsertUseConfig { |
| granularity: ImportGranularity::Item, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: false, |
| skip_glob_imports: true, |
| }, |
| ); |
| } |
| |
| #[test] |
| fn insert_empty_module() { |
| cov_mark::check_count!(insert_empty_module, 2); |
| |
| // Default configuration |
| check( |
| "foo::bar", |
| r" |
| mod x {$0} |
| ", |
| r" |
| mod x { |
| use foo::bar; |
| } |
| ", |
| ImportGranularity::Item, |
| ); |
| |
| // "not group" configuration |
| check_with_config( |
| "foo::bar", |
| r"mod x {$0}", |
| r"mod x { |
| use foo::bar; |
| }", |
| &InsertUseConfig { |
| granularity: ImportGranularity::Item, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: false, |
| skip_glob_imports: true, |
| }, |
| ); |
| } |
| |
| #[test] |
| fn insert_after_inner_attr() { |
| cov_mark::check_count!(insert_empty_inner_attr, 2); |
| |
| // Default configuration |
| check_crate( |
| "foo::bar", |
| r"#![allow(unused_imports)]", |
| r"#![allow(unused_imports)] |
| |
| use foo::bar;", |
| ); |
| |
| // "not group" configuration |
| check_with_config( |
| "foo::bar", |
| r"#![allow(unused_imports)]", |
| r"#![allow(unused_imports)] |
| |
| use foo::bar;", |
| &InsertUseConfig { |
| granularity: ImportGranularity::Item, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: false, |
| skip_glob_imports: true, |
| }, |
| ); |
| } |
| |
| #[test] |
| fn insert_after_inner_attr2() { |
| check_crate( |
| "foo::bar", |
| r"#![allow(unused_imports)] |
| |
| #![no_std] |
| fn main() {}", |
| r"#![allow(unused_imports)] |
| |
| #![no_std] |
| |
| use foo::bar; |
| fn main() {}", |
| ); |
| } |
| |
| #[test] |
| fn inserts_after_single_line_inner_comments() { |
| check_none( |
| "foo::bar::Baz", |
| "//! Single line inner comments do not allow any code before them.", |
| r#"//! Single line inner comments do not allow any code before them. |
| |
| use foo::bar::Baz;"#, |
| ); |
| check_none( |
| "foo::bar::Baz", |
| r"mod foo { |
| //! Single line inner comments do not allow any code before them. |
| $0 |
| }", |
| r"mod foo { |
| //! Single line inner comments do not allow any code before them. |
| |
| use foo::bar::Baz; |
| |
| }", |
| ); |
| } |
| |
| #[test] |
| fn inserts_after_single_line_comments() { |
| check_none( |
| "foo::bar::Baz", |
| "// Represents a possible license header and/or general module comments", |
| r#"// Represents a possible license header and/or general module comments |
| |
| use foo::bar::Baz;"#, |
| ); |
| } |
| |
| #[test] |
| fn inserts_after_shebang() { |
| check_none( |
| "foo::bar::Baz", |
| "#!/usr/bin/env rust", |
| r#"#!/usr/bin/env rust |
| |
| use foo::bar::Baz;"#, |
| ); |
| } |
| |
| #[test] |
| fn inserts_after_multiple_single_line_comments() { |
| check_none( |
| "foo::bar::Baz", |
| "// Represents a possible license header and/or general module comments |
| // Second single-line comment |
| // Third single-line comment", |
| r#"// Represents a possible license header and/or general module comments |
| // Second single-line comment |
| // Third single-line comment |
| |
| use foo::bar::Baz;"#, |
| ); |
| } |
| |
| #[test] |
| fn inserts_before_single_line_item_comments() { |
| check_none( |
| "foo::bar::Baz", |
| r#"// Represents a comment about a function |
| fn foo() {}"#, |
| r#"use foo::bar::Baz; |
| |
| // Represents a comment about a function |
| fn foo() {}"#, |
| ); |
| } |
| |
| #[test] |
| fn inserts_after_single_line_header_comments_and_before_item() { |
| check_none( |
| "foo::bar::Baz", |
| r#"// Represents a possible license header |
| // Line two of possible license header |
| |
| fn foo() {}"#, |
| r#"// Represents a possible license header |
| // Line two of possible license header |
| |
| use foo::bar::Baz; |
| |
| fn foo() {}"#, |
| ); |
| } |
| |
| #[test] |
| fn inserts_after_multiline_inner_comments() { |
| check_none( |
| "foo::bar::Baz", |
| r#"/*! Multiline inner comments do not allow any code before them. */ |
| |
| /*! Still an inner comment, cannot place any code before. */ |
| fn main() {}"#, |
| r#"/*! Multiline inner comments do not allow any code before them. */ |
| |
| /*! Still an inner comment, cannot place any code before. */ |
| |
| use foo::bar::Baz; |
| fn main() {}"#, |
| ) |
| } |
| |
| #[test] |
| fn inserts_after_all_inner_items() { |
| check_none( |
| "foo::bar::Baz", |
| r#"#![allow(unused_imports)] |
| /*! Multiline line comment 2 */ |
| |
| |
| //! Single line comment 1 |
| #![no_std] |
| //! Single line comment 2 |
| fn main() {}"#, |
| r#"#![allow(unused_imports)] |
| /*! Multiline line comment 2 */ |
| |
| |
| //! Single line comment 1 |
| #![no_std] |
| //! Single line comment 2 |
| |
| use foo::bar::Baz; |
| fn main() {}"#, |
| ) |
| } |
| |
| #[test] |
| fn merge_groups() { |
| check_module("std::io", r"use std::fmt;", r"use std::{fmt, io};"); |
| check_one("std::io", r"use {std::fmt};", r"use {std::{fmt, io}};"); |
| check_one("std::io", r"use std::fmt;", r"use {std::{fmt, io}};"); |
| } |
| |
| #[test] |
| fn merge_groups_last() { |
| check_module( |
| "std::io", |
| r"use std::fmt::{Result, Display};", |
| r"use std::fmt::{Result, Display}; |
| use std::io;", |
| ); |
| check_one( |
| "std::io", |
| r"use {std::fmt::{Result, Display}};", |
| r"use {std::{fmt::{Display, Result}, io}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_last_into_self() { |
| check_module("foo::bar::baz", r"use foo::bar;", r"use foo::bar::{self, baz};"); |
| check_one("foo::bar::baz", r"use {foo::bar};", r"use {foo::bar::{self, baz}};"); |
| } |
| |
| #[test] |
| fn merge_groups_full() { |
| check_crate( |
| "std::io", |
| r"use std::fmt::{Result, Display};", |
| r"use std::{fmt::{Display, Result}, io};", |
| ); |
| check_one( |
| "std::io", |
| r"use {std::fmt::{Result, Display}};", |
| r"use {std::{fmt::{Display, Result}, io}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_long_full() { |
| check_crate( |
| "std::foo::bar::Baz", |
| r"use std::foo::bar::Qux;", |
| r"use std::foo::bar::{Baz, Qux};", |
| ); |
| check_crate( |
| "std::foo::bar::r#Baz", |
| r"use std::foo::bar::Qux;", |
| r"use std::foo::bar::{r#Baz, Qux};", |
| ); |
| check_one( |
| "std::foo::bar::Baz", |
| r"use {std::foo::bar::Qux};", |
| r"use {std::foo::bar::{Baz, Qux}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_long_last() { |
| check_module( |
| "std::foo::bar::Baz", |
| r"use std::foo::bar::Qux;", |
| r"use std::foo::bar::{Baz, Qux};", |
| ) |
| } |
| |
| #[test] |
| fn merge_groups_long_full_list() { |
| check_crate( |
| "std::foo::bar::Baz", |
| r"use std::foo::bar::{Qux, Quux};", |
| r"use std::foo::bar::{Baz, Quux, Qux};", |
| ); |
| check_crate( |
| "std::foo::bar::r#Baz", |
| r"use std::foo::bar::{Qux, Quux};", |
| r"use std::foo::bar::{r#Baz, Quux, Qux};", |
| ); |
| check_one( |
| "std::foo::bar::Baz", |
| r"use {std::foo::bar::{Qux, Quux}};", |
| r"use {std::foo::bar::{Baz, Quux, Qux}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_long_last_list() { |
| check_module( |
| "std::foo::bar::Baz", |
| r"use std::foo::bar::{Qux, Quux};", |
| r"use std::foo::bar::{Baz, Quux, Qux};", |
| ) |
| } |
| |
| #[test] |
| fn merge_groups_long_full_nested() { |
| check_crate( |
| "std::foo::bar::Baz", |
| r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
| r"use std::foo::bar::{quux::{Fez, Fizz}, Baz, Qux};", |
| ); |
| check_crate( |
| "std::foo::bar::r#Baz", |
| r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
| r"use std::foo::bar::{quux::{Fez, Fizz}, r#Baz, Qux};", |
| ); |
| check_one( |
| "std::foo::bar::Baz", |
| r"use {std::foo::bar::{Qux, quux::{Fez, Fizz}}};", |
| r"use {std::foo::bar::{quux::{Fez, Fizz}, Baz, Qux}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_long_last_nested() { |
| check_module( |
| "std::foo::bar::Baz", |
| r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
| r"use std::foo::bar::Baz; |
| use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
| ) |
| } |
| |
| #[test] |
| fn merge_groups_full_nested_deep() { |
| check_crate( |
| "std::foo::bar::quux::Baz", |
| r"use std::foo::bar::{Qux, quux::{Fez, Fizz}};", |
| r"use std::foo::bar::{quux::{Baz, Fez, Fizz}, Qux};", |
| ); |
| check_one( |
| "std::foo::bar::quux::Baz", |
| r"use {std::foo::bar::{Qux, quux::{Fez, Fizz}}};", |
| r"use {std::foo::bar::{quux::{Baz, Fez, Fizz}, Qux}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_full_nested_long() { |
| check_crate( |
| "std::foo::bar::Baz", |
| r"use std::{foo::bar::Qux};", |
| r"use std::foo::bar::{Baz, Qux};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_last_nested_long() { |
| check_crate( |
| "std::foo::bar::Baz", |
| r"use std::{foo::bar::Qux};", |
| r"use std::foo::bar::{Baz, Qux};", |
| ); |
| check_one( |
| "std::foo::bar::Baz", |
| r"use {std::{foo::bar::Qux}};", |
| r"use {std::foo::bar::{Baz, Qux}};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_skip_pub() { |
| check_crate( |
| "std::io", |
| r"pub use std::fmt::{Result, Display};", |
| r"pub use std::fmt::{Result, Display}; |
| use std::io;", |
| ); |
| check_one( |
| "std::io", |
| r"pub use {std::fmt::{Result, Display}};", |
| r"pub use {std::fmt::{Result, Display}}; |
| use {std::io};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_skip_pub_crate() { |
| check_crate( |
| "std::io", |
| r"pub(crate) use std::fmt::{Result, Display};", |
| r"pub(crate) use std::fmt::{Result, Display}; |
| use std::io;", |
| ); |
| check_one( |
| "std::io", |
| r"pub(crate) use {std::fmt::{Result, Display}};", |
| r"pub(crate) use {std::fmt::{Result, Display}}; |
| use {std::io};", |
| ); |
| } |
| |
| #[test] |
| fn merge_groups_skip_attributed() { |
| check_crate( |
| "std::io", |
| r#" |
| #[cfg(feature = "gated")] use std::fmt::{Result, Display}; |
| "#, |
| r#" |
| #[cfg(feature = "gated")] use std::fmt::{Result, Display}; |
| use std::io; |
| "#, |
| ); |
| check_one( |
| "std::io", |
| r#" |
| #[cfg(feature = "gated")] use {std::fmt::{Result, Display}}; |
| "#, |
| r#" |
| #[cfg(feature = "gated")] use {std::fmt::{Result, Display}}; |
| use {std::io}; |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn split_out_merge() { |
| // FIXME: This is suboptimal, we want to get `use std::fmt::{self, Result}` |
| // instead. |
| check_module( |
| "std::fmt::Result", |
| r"use std::{fmt, io};", |
| r"use std::fmt::Result; |
| use std::{fmt, io};", |
| ) |
| } |
| |
| #[test] |
| fn merge_into_module_import() { |
| check_crate("std::fmt::Result", r"use std::{fmt, io};", r"use std::{fmt::{self, Result}, io};") |
| } |
| |
| #[test] |
| fn merge_groups_self() { |
| check_crate("std::fmt::Debug", r"use std::fmt;", r"use std::fmt::{self, Debug};") |
| } |
| |
| #[test] |
| fn merge_mod_into_glob() { |
| check_with_config( |
| "token::TokenKind", |
| r"use token::TokenKind::*;", |
| r"use token::TokenKind::{self, *};", |
| &InsertUseConfig { |
| granularity: ImportGranularity::Crate, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: false, |
| skip_glob_imports: false, |
| }, |
| ) |
| } |
| |
| #[test] |
| fn merge_self_glob() { |
| check_with_config( |
| "self", |
| r"use self::*;", |
| r"use self::{self, *};", |
| &InsertUseConfig { |
| granularity: ImportGranularity::Crate, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: false, |
| skip_glob_imports: false, |
| }, |
| ) |
| } |
| |
| #[test] |
| fn merge_glob() { |
| check_crate( |
| "syntax::SyntaxKind", |
| r" |
| use syntax::{SyntaxKind::*};", |
| r" |
| use syntax::SyntaxKind::{self, *};", |
| ) |
| } |
| |
| #[test] |
| fn merge_glob_nested() { |
| check_crate( |
| "foo::bar::quux::Fez", |
| r"use foo::bar::{Baz, quux::*};", |
| r"use foo::bar::{quux::{Fez, *}, Baz};", |
| ) |
| } |
| |
| #[test] |
| fn merge_nested_considers_first_segments() { |
| check_crate( |
| "hir_ty::display::write_bounds_like_dyn_trait", |
| r"use hir_ty::{autoderef, display::{HirDisplayError, HirFormatter}, method_resolution};", |
| r"use hir_ty::{autoderef, display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter}, method_resolution};", |
| ); |
| } |
| |
| #[test] |
| fn skip_merge_last_too_long() { |
| check_module( |
| "foo::bar", |
| r"use foo::bar::baz::Qux;", |
| r"use foo::bar; |
| use foo::bar::baz::Qux;", |
| ); |
| } |
| |
| #[test] |
| fn skip_merge_last_too_long2() { |
| check_module( |
| "foo::bar::baz::Qux", |
| r"use foo::bar;", |
| r"use foo::bar; |
| use foo::bar::baz::Qux;", |
| ); |
| } |
| |
| #[test] |
| fn insert_short_before_long() { |
| check_none( |
| "foo::bar", |
| r"use foo::bar::baz::Qux;", |
| r"use foo::bar; |
| use foo::bar::baz::Qux;", |
| ); |
| } |
| |
| #[test] |
| fn merge_last_fail() { |
| check_merge_only_fail( |
| r"use foo::bar::{baz::{Qux, Fez}};", |
| r"use foo::bar::{baaz::{Quux, Feez}};", |
| MergeBehavior::Module, |
| ); |
| } |
| |
| #[test] |
| fn merge_last_fail1() { |
| check_merge_only_fail( |
| r"use foo::bar::{baz::{Qux, Fez}};", |
| r"use foo::bar::baaz::{Quux, Feez};", |
| MergeBehavior::Module, |
| ); |
| } |
| |
| #[test] |
| fn merge_last_fail2() { |
| check_merge_only_fail( |
| r"use foo::bar::baz::{Qux, Fez};", |
| r"use foo::bar::{baaz::{Quux, Feez}};", |
| MergeBehavior::Module, |
| ); |
| } |
| |
| #[test] |
| fn merge_last_fail3() { |
| check_merge_only_fail( |
| r"use foo::bar::baz::{Qux, Fez};", |
| r"use foo::bar::baaz::{Quux, Feez};", |
| MergeBehavior::Module, |
| ); |
| } |
| |
| #[test] |
| fn guess_empty() { |
| check_guess("", ImportGranularityGuess::Unknown); |
| } |
| |
| #[test] |
| fn guess_single() { |
| check_guess(r"use foo::{baz::{qux, quux}, bar};", ImportGranularityGuess::Crate); |
| check_guess(r"use foo::bar;", ImportGranularityGuess::Unknown); |
| check_guess(r"use foo::bar::{baz, qux};", ImportGranularityGuess::CrateOrModule); |
| check_guess(r"use {foo::bar};", ImportGranularityGuess::One); |
| } |
| |
| #[test] |
| fn guess_unknown() { |
| check_guess( |
| r" |
| use foo::bar::baz; |
| use oof::rab::xuq; |
| ", |
| ImportGranularityGuess::Unknown, |
| ); |
| } |
| |
| #[test] |
| fn guess_item() { |
| check_guess( |
| r" |
| use foo::bar::baz; |
| use foo::bar::qux; |
| ", |
| ImportGranularityGuess::Item, |
| ); |
| } |
| |
| #[test] |
| fn guess_module_or_item() { |
| check_guess( |
| r" |
| use foo::bar::Bar; |
| use foo::qux; |
| ", |
| ImportGranularityGuess::ModuleOrItem, |
| ); |
| check_guess( |
| r" |
| use foo::bar::Bar; |
| use foo::bar; |
| ", |
| ImportGranularityGuess::ModuleOrItem, |
| ); |
| } |
| |
| #[test] |
| fn guess_module() { |
| check_guess( |
| r" |
| use foo::bar::baz; |
| use foo::bar::{qux, quux}; |
| ", |
| ImportGranularityGuess::Module, |
| ); |
| // this is a rather odd case, technically this file isn't following any style properly. |
| check_guess( |
| r" |
| use foo::bar::baz; |
| use foo::{baz::{qux, quux}, bar}; |
| ", |
| ImportGranularityGuess::Module, |
| ); |
| check_guess( |
| r" |
| use foo::bar::Bar; |
| use foo::baz::Baz; |
| use foo::{Foo, Qux}; |
| ", |
| ImportGranularityGuess::Module, |
| ); |
| } |
| |
| #[test] |
| fn guess_crate_or_module() { |
| check_guess( |
| r" |
| use foo::bar::baz; |
| use oof::bar::{qux, quux}; |
| ", |
| ImportGranularityGuess::CrateOrModule, |
| ); |
| } |
| |
| #[test] |
| fn guess_crate() { |
| check_guess( |
| r" |
| use frob::bar::baz; |
| use foo::{baz::{qux, quux}, bar}; |
| ", |
| ImportGranularityGuess::Crate, |
| ); |
| } |
| |
| #[test] |
| fn guess_one() { |
| check_guess( |
| r" |
| use { |
| frob::bar::baz, |
| foo::{baz::{qux, quux}, bar} |
| }; |
| ", |
| ImportGranularityGuess::One, |
| ); |
| } |
| |
| #[test] |
| fn guess_skips_differing_vis() { |
| check_guess( |
| r" |
| use foo::bar::baz; |
| pub use foo::bar::qux; |
| ", |
| ImportGranularityGuess::Unknown, |
| ); |
| } |
| |
| #[test] |
| fn guess_one_differing_vis() { |
| check_guess( |
| r" |
| use {foo::bar::baz}; |
| pub use {foo::bar::qux}; |
| ", |
| ImportGranularityGuess::One, |
| ); |
| } |
| |
| #[test] |
| fn guess_skips_multiple_one_style_same_vis() { |
| check_guess( |
| r" |
| use {foo::bar::baz}; |
| use {foo::bar::qux}; |
| ", |
| ImportGranularityGuess::Unknown, |
| ); |
| } |
| |
| #[test] |
| fn guess_skips_differing_attrs() { |
| check_guess( |
| r" |
| pub use foo::bar::baz; |
| #[doc(hidden)] |
| pub use foo::bar::qux; |
| ", |
| ImportGranularityGuess::Unknown, |
| ); |
| } |
| |
| #[test] |
| fn guess_one_differing_attrs() { |
| check_guess( |
| r" |
| pub use {foo::bar::baz}; |
| #[doc(hidden)] |
| pub use {foo::bar::qux}; |
| ", |
| ImportGranularityGuess::One, |
| ); |
| } |
| |
| #[test] |
| fn guess_skips_multiple_one_style_same_attrs() { |
| check_guess( |
| r" |
| #[doc(hidden)] |
| use {foo::bar::baz}; |
| #[doc(hidden)] |
| use {foo::bar::qux}; |
| ", |
| ImportGranularityGuess::Unknown, |
| ); |
| } |
| |
| #[test] |
| fn guess_grouping_matters() { |
| check_guess( |
| r" |
| use foo::bar::baz; |
| use oof::bar::baz; |
| use foo::bar::qux; |
| ", |
| ImportGranularityGuess::Unknown, |
| ); |
| } |
| |
| #[test] |
| fn insert_with_renamed_import_simple_use() { |
| check_with_config( |
| "use self::foo::Foo", |
| r#" |
| use self::foo::Foo as _; |
| "#, |
| r#" |
| use self::foo::Foo; |
| "#, |
| &InsertUseConfig { |
| granularity: ImportGranularity::Crate, |
| prefix_kind: hir::PrefixKind::BySelf, |
| enforce_granularity: true, |
| group: true, |
| skip_glob_imports: true, |
| }, |
| ); |
| } |
| |
| #[test] |
| fn insert_with_renamed_import_complex_use() { |
| check_with_config( |
| "use self::foo::Foo;", |
| r#" |
| use self::foo::{self, Foo as _, Bar}; |
| "#, |
| r#" |
| use self::foo::{self, Bar, Foo}; |
| "#, |
| &InsertUseConfig { |
| granularity: ImportGranularity::Crate, |
| prefix_kind: hir::PrefixKind::BySelf, |
| enforce_granularity: true, |
| group: true, |
| skip_glob_imports: true, |
| }, |
| ); |
| } |
| |
| fn check_with_config( |
| path: &str, |
| ra_fixture_before: &str, |
| ra_fixture_after: &str, |
| config: &InsertUseConfig, |
| ) { |
| let (db, file_id, pos) = if ra_fixture_before.contains(CURSOR_MARKER) { |
| let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture_before); |
| (db, file_id, Some(range_or_offset)) |
| } else { |
| let (db, file_id) = RootDatabase::with_single_file(ra_fixture_before); |
| (db, file_id, None) |
| }; |
| let sema = &Semantics::new(&db); |
| let source_file = sema.parse(file_id); |
| let syntax = source_file.syntax().clone_for_update(); |
| let file = pos |
| .and_then(|pos| syntax.token_at_offset(pos.expect_offset()).next()?.parent()) |
| .and_then(|it| ImportScope::find_insert_use_container(&it, sema)) |
| .or_else(|| ImportScope::from(syntax)) |
| .unwrap(); |
| let path = ast::SourceFile::parse(&format!("use {path};")) |
| .tree() |
| .syntax() |
| .descendants() |
| .find_map(ast::Path::cast) |
| .unwrap(); |
| |
| insert_use(&file, path, config); |
| let result = file.as_syntax_node().ancestors().last().unwrap().to_string(); |
| assert_eq_text!(&trim_indent(ra_fixture_after), &result); |
| } |
| |
| fn check( |
| path: &str, |
| ra_fixture_before: &str, |
| ra_fixture_after: &str, |
| granularity: ImportGranularity, |
| ) { |
| check_with_config( |
| path, |
| ra_fixture_before, |
| ra_fixture_after, |
| &InsertUseConfig { |
| granularity, |
| enforce_granularity: true, |
| prefix_kind: PrefixKind::Plain, |
| group: true, |
| skip_glob_imports: true, |
| }, |
| ) |
| } |
| |
| fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
| check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate) |
| } |
| |
| fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
| check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module) |
| } |
| |
| fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
| check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item) |
| } |
| |
| fn check_one(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
| check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::One) |
| } |
| |
| fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { |
| let use0 = ast::SourceFile::parse(ra_fixture0) |
| .tree() |
| .syntax() |
| .descendants() |
| .find_map(ast::Use::cast) |
| .unwrap(); |
| |
| let use1 = ast::SourceFile::parse(ra_fixture1) |
| .tree() |
| .syntax() |
| .descendants() |
| .find_map(ast::Use::cast) |
| .unwrap(); |
| |
| let result = try_merge_imports(&use0, &use1, mb); |
| assert_eq!(result.map(|u| u.to_string()), None); |
| } |
| |
| fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) { |
| let syntax = ast::SourceFile::parse(ra_fixture).tree().syntax().clone(); |
| let file = ImportScope::from(syntax).unwrap(); |
| assert_eq!(super::guess_granularity_from_scope(&file), expected); |
| } |