@@ -174,3 +174,122 @@ 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
+ /// 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