Skip to content

Commit 35130a3

Browse files
committed
Add test to validate the config loading rules
Configs are loaded in the following order: 1. Load configs from the `--config-path` option 2. Travers the directory hierarchy looking for a config file 3. Check the user's `HOME` directory for a config file 4. Check the user's config directory for a config file
1 parent 1b5f8ef commit 35130a3

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed

tests/rustfmt/main.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,122 @@ fn rustfmt_emits_error_on_line_overflow_true() {
174174
"line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
175175
))
176176
}
177+
178+
/// helper function to write a new rustfmt.toml to a file
179+
fn write_rustfmt_toml<P: AsRef<Path>>(path: P) {
180+
let dir_path = if path.as_ref().is_dir() {
181+
path.as_ref()
182+
} else {
183+
path.as_ref().parent().unwrap()
184+
};
185+
186+
rustfmt(&[
187+
"--print-config=default",
188+
&dir_path.join("rustfmt.toml").display().to_string(),
189+
]);
190+
}
191+
192+
/// helper function to turn an AsRef<Path> into a String
193+
fn path_arg<P: AsRef<Path>>(path: P) -> String {
194+
path.as_ref().display().to_string()
195+
}
196+
197+
macro_rules! assert_using_expected_config {
198+
($file_path:expr) => {
199+
// case where we don't specify a config
200+
// No configs should exist in the file system when calling this case
201+
let (stdout, _stderr) = rustfmt(&["-v", &path_arg($file_path)]);
202+
assert!(!stdout.contains("rustfmt.toml"));
203+
};
204+
205+
($file_path:expr, $config_dir:expr) => {
206+
// case where we expect a config to be implicitly loaded
207+
let (stdout, _stderr) = rustfmt(&["-v", &path_arg($file_path)]);
208+
assert!(stdout.contains(&path_arg($config_dir)));
209+
};
210+
211+
($file_path:expr, "--config-path", $config_path:expr) => {
212+
// case where we explictly set a config and ensure it gets loaded
213+
let (stdout, _stderr) = rustfmt(&[
214+
"-v",
215+
"--config-path",
216+
&path_arg($config_path),
217+
&path_arg($file_path),
218+
]);
219+
assert!(stdout.contains(&path_arg($config_path)));
220+
};
221+
}
222+
223+
/// Ensure that we're loading the correct config when running rustfmt
224+
///
225+
/// Configs are loaded in the following order:
226+
/// 1. Load configs from the `--config-path` option.
227+
/// 2. Travers the directory hierarchy looking for a config file
228+
/// 3. Check the user's `HOME` directory for a config file (could vary by platform)
229+
/// 4. Check the user's config directory for a config file (could vary by platform)
230+
///
231+
/// When no configs are found rustfmt is run with just the default options.
232+
#[cfg(not(windows))]
233+
#[test]
234+
fn test_load_config_logic() {
235+
// Create a temporary directory and set it as the new $HOME.
236+
// This sets up a clean environment that we'll use to test the config loading logic
237+
let tmpdir = tempfile::tempdir().unwrap();
238+
let _home_env = tmp_env::set_var("HOME", tmpdir.as_ref());
239+
240+
// Sanity check to make sure that we set the $HOME directory
241+
let home_dir = dirs::home_dir().unwrap();
242+
assert_eq!(tmpdir.as_ref(), home_dir.as_path());
243+
244+
// Create a working directory nested a few levels deep inside the temporary $HOME.
245+
// We want a few directory levels so we can properly test case #2 listed above.
246+
// Set the current working directory to the new path so we don't pick up any rustfmt.toml
247+
// files defined outside our clean environment.
248+
let work_dir = home_dir.join("path").join("to").join("file");
249+
std::fs::create_dir_all(&work_dir).unwrap();
250+
let _current_dir = tmp_env::set_current_dir(&work_dir).unwrap();
251+
252+
// Set up the user's config directory
253+
let mut config_dir = dirs::config_dir().unwrap();
254+
config_dir.push("rustfmt");
255+
std::fs::create_dir_all(&config_dir).unwrap();
256+
257+
// Write a hello world file used for formatting checks in the working directory
258+
let file_path = work_dir.join("test.rs");
259+
std::fs::write(
260+
&file_path,
261+
"fn main() {\n println!(\"Hello world!\");\n}",
262+
)
263+
.unwrap();
264+
265+
// 1. Run rustfmt and make sure we don't load any configs
266+
assert_using_expected_config!(&file_path);
267+
268+
// Write a rustfmt.toml to the users config directory
269+
// 2. Run rustfmt and make sure we load the config from the user's config dir.
270+
// Sinces no other configs exist this one should be used.
271+
write_rustfmt_toml(&config_dir);
272+
assert_using_expected_config!(&file_path, &config_dir);
273+
274+
// Write a rustfmt.toml to the users $HOME directory
275+
// 3. Run rustmft and make sure we load the config from the user's $HOME dir
276+
// Configs in the $HOME dir take precedence over those in the config dir
277+
write_rustfmt_toml(&home_dir);
278+
assert_using_expected_config!(&file_path, &home_dir);
279+
280+
// write a rustfmt.toml to some directory in the `work_dir` hierarchy.
281+
// 4. Run rustfmt and make sure we load the config from the file hierarcy.
282+
// Configs found in the file hierarcy take precedence to those in $HOME and the config dir.
283+
let config_along_path = work_dir.parent().unwrap().parent().unwrap();
284+
write_rustfmt_toml(&config_along_path);
285+
assert_using_expected_config!(&file_path, &config_along_path);
286+
287+
// write a rustfmt.toml outside the working directory hierarchy.
288+
// This ensures it isn't automatically picked up.
289+
// 5. run rustfmt and explicitly set the `--config-path` option to this config file.
290+
// Configs that are explicity set take precedence over all other configs.
291+
let explicit_config_path = home_dir.join("new").join("config").join("path");
292+
std::fs::create_dir_all(&explicit_config_path).unwrap();
293+
write_rustfmt_toml(&explicit_config_path);
294+
assert_using_expected_config!(&file_path, "--config-path", &explicit_config_path);
295+
}

0 commit comments

Comments
 (0)