From 35130a3330fc5a7f052cb08c1a5cb38d1ab4b0a3 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Mon, 22 Aug 2022 12:17:08 -0400 Subject: [PATCH] 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 --- tests/rustfmt/main.rs | 119 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index 7ff301e8019..b085d64ad66 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -174,3 +174,122 @@ fn rustfmt_emits_error_on_line_overflow_true() { "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)" )) } + +/// helper function to write a new rustfmt.toml to a file +fn write_rustfmt_toml>(path: P) { + let dir_path = if path.as_ref().is_dir() { + path.as_ref() + } else { + path.as_ref().parent().unwrap() + }; + + rustfmt(&[ + "--print-config=default", + &dir_path.join("rustfmt.toml").display().to_string(), + ]); +} + +/// helper function to turn an AsRef into a String +fn path_arg>(path: P) -> String { + path.as_ref().display().to_string() +} + +macro_rules! assert_using_expected_config { + ($file_path:expr) => { + // case where we don't specify a config + // No configs should exist in the file system when calling this case + let (stdout, _stderr) = rustfmt(&["-v", &path_arg($file_path)]); + assert!(!stdout.contains("rustfmt.toml")); + }; + + ($file_path:expr, $config_dir:expr) => { + // case where we expect a config to be implicitly loaded + let (stdout, _stderr) = rustfmt(&["-v", &path_arg($file_path)]); + assert!(stdout.contains(&path_arg($config_dir))); + }; + + ($file_path:expr, "--config-path", $config_path:expr) => { + // case where we explictly set a config and ensure it gets loaded + let (stdout, _stderr) = rustfmt(&[ + "-v", + "--config-path", + &path_arg($config_path), + &path_arg($file_path), + ]); + assert!(stdout.contains(&path_arg($config_path))); + }; +} + +/// Ensure that we're loading the correct config when running rustfmt +/// +/// 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 (could vary by platform) +/// 4. Check the user's config directory for a config file (could vary by platform) +/// +/// When no configs are found rustfmt is run with just the default options. +#[cfg(not(windows))] +#[test] +fn test_load_config_logic() { + // Create a temporary directory and set it as the new $HOME. + // This sets up a clean environment that we'll use to test the config loading logic + let tmpdir = tempfile::tempdir().unwrap(); + let _home_env = tmp_env::set_var("HOME", tmpdir.as_ref()); + + // Sanity check to make sure that we set the $HOME directory + let home_dir = dirs::home_dir().unwrap(); + assert_eq!(tmpdir.as_ref(), home_dir.as_path()); + + // Create a working directory nested a few levels deep inside the temporary $HOME. + // We want a few directory levels so we can properly test case #2 listed above. + // Set the current working directory to the new path so we don't pick up any rustfmt.toml + // files defined outside our clean environment. + let work_dir = home_dir.join("path").join("to").join("file"); + std::fs::create_dir_all(&work_dir).unwrap(); + let _current_dir = tmp_env::set_current_dir(&work_dir).unwrap(); + + // Set up the user's config directory + let mut config_dir = dirs::config_dir().unwrap(); + config_dir.push("rustfmt"); + std::fs::create_dir_all(&config_dir).unwrap(); + + // Write a hello world file used for formatting checks in the working directory + let file_path = work_dir.join("test.rs"); + std::fs::write( + &file_path, + "fn main() {\n println!(\"Hello world!\");\n}", + ) + .unwrap(); + + // 1. Run rustfmt and make sure we don't load any configs + assert_using_expected_config!(&file_path); + + // Write a rustfmt.toml to the users config directory + // 2. Run rustfmt and make sure we load the config from the user's config dir. + // Sinces no other configs exist this one should be used. + write_rustfmt_toml(&config_dir); + assert_using_expected_config!(&file_path, &config_dir); + + // Write a rustfmt.toml to the users $HOME directory + // 3. Run rustmft and make sure we load the config from the user's $HOME dir + // Configs in the $HOME dir take precedence over those in the config dir + write_rustfmt_toml(&home_dir); + assert_using_expected_config!(&file_path, &home_dir); + + // write a rustfmt.toml to some directory in the `work_dir` hierarchy. + // 4. Run rustfmt and make sure we load the config from the file hierarcy. + // Configs found in the file hierarcy take precedence to those in $HOME and the config dir. + let config_along_path = work_dir.parent().unwrap().parent().unwrap(); + write_rustfmt_toml(&config_along_path); + assert_using_expected_config!(&file_path, &config_along_path); + + // write a rustfmt.toml outside the working directory hierarchy. + // This ensures it isn't automatically picked up. + // 5. run rustfmt and explicitly set the `--config-path` option to this config file. + // Configs that are explicity set take precedence over all other configs. + let explicit_config_path = home_dir.join("new").join("config").join("path"); + std::fs::create_dir_all(&explicit_config_path).unwrap(); + write_rustfmt_toml(&explicit_config_path); + assert_using_expected_config!(&file_path, "--config-path", &explicit_config_path); +}