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