@@ -281,4 +281,142 @@ class Foo
281281 RUBY
282282 end
283283 end
284+
285+ # We intentionally isolate all of the plugin specs in this context
286+ # rubocop:disable RSpec/NestedGroups
287+ context 'when using ActiveSupport integration' do
288+ around do |example |
289+ reset_activesupport_cache!
290+ example . run
291+ reset_activesupport_cache!
292+ end
293+
294+ def reset_activesupport_cache!
295+ described_class ::ActiveSupportInflector . instance_variable_set (
296+ :@prepared , nil
297+ )
298+ end
299+
300+ let ( :cop_config ) do
301+ {
302+ 'EnforcedInflector' => 'active_support' ,
303+ 'InflectorPath' => './config/initializers/inflections.rb'
304+ }
305+ end
306+
307+ context 'when ActiveSupport inflections are available' do
308+ before do
309+ allow ( File ) . to receive ( :exist? )
310+ . with ( cop_config [ 'InflectorPath' ] ) . and_return ( true )
311+
312+ allow ( described_class ::ActiveSupportInflector ) . to receive ( :require )
313+ . with ( 'active_support/inflector' )
314+ stub_const ( 'ActiveSupport::Inflector' ,
315+ Module . new { def self . underscore ( _ ) ; end } )
316+
317+ allow ( described_class ::ActiveSupportInflector ) . to receive ( :require )
318+ . with ( './config/initializers/inflections.rb' )
319+ allow ( ActiveSupport ::Inflector ) . to receive ( :underscore )
320+ . with ( 'PvPClass' ) . and_return ( 'pvp_class' )
321+ allow ( ActiveSupport ::Inflector ) . to receive ( :underscore )
322+ . with ( 'HTTPClient' ) . and_return ( 'http_client' )
323+ allow ( ActiveSupport ::Inflector ) . to receive ( :underscore )
324+ . with ( 'HTTPSClient' ) . and_return ( 'https_client' )
325+ allow ( ActiveSupport ::Inflector ) . to receive ( :underscore )
326+ . with ( 'API' ) . and_return ( 'api' )
327+ end
328+
329+ it 'uses ActiveSupport inflections for custom acronyms' do
330+ expect_no_offenses ( <<~RUBY , 'pvp_class_spec.rb' )
331+ describe PvPClass do; end
332+ RUBY
333+ end
334+
335+ it 'registers an offense when ActiveSupport inflections ' \
336+ 'suggest different path' do
337+ expect_offense ( <<~RUBY , 'pv_p_class_spec.rb' )
338+ describe PvPClass do; end
339+ ^^^^^^^^^^^^^^^^^ Spec path should end with `pvp_class*_spec.rb`.
340+ RUBY
341+ end
342+
343+ it 'does not register complex acronyms with method names' do
344+ expect_no_offenses ( <<~RUBY , 'pvp_class_foo_spec.rb' )
345+ describe PvPClass, 'foo' do; end
346+ RUBY
347+ end
348+
349+ it 'does not register nested namespaces with custom acronyms' do
350+ expect_no_offenses ( <<~RUBY , 'api/http_client_spec.rb' )
351+ describe API::HTTPClient do; end
352+ RUBY
353+ end
354+ end
355+
356+ describe 'errors during preparation' do
357+ it 'shows an error when the configured inflector file does not exist' do
358+ allow ( File ) . to receive ( :exist? )
359+ . with ( cop_config [ 'InflectorPath' ] ) . and_return ( false )
360+
361+ expect do
362+ inspect_source ( 'describe PvPClass do; end' , 'pv_p_class_spec.rb' )
363+ end . to raise_error ( 'The configured `InflectorPath` ./config' \
364+ '/initializers/inflections.rb does not exist.' )
365+ end
366+
367+ it 'lets LoadError pass all the way up when ActiveSupport loading ' \
368+ 'raises an error' do
369+ allow ( File ) . to receive ( :exist? )
370+ . with ( cop_config [ 'InflectorPath' ] ) . and_return ( true )
371+
372+ allow ( described_class ::ActiveSupportInflector ) . to receive ( :require )
373+ . with ( 'active_support/inflector' ) . and_raise ( LoadError )
374+
375+ expect do
376+ inspect_source ( 'describe PvPClass do; end' , 'pv_p_class_spec.rb' )
377+ end . to raise_error ( LoadError )
378+ end
379+ end
380+
381+ context 'when testing custom InflectorPath configuration precedence' do
382+ let ( :cop_config ) do
383+ {
384+ 'EnforcedInflector' => 'active_support' ,
385+ 'InflectorPath' => '/custom/path/to/inflections.rb'
386+ }
387+ end
388+
389+ before do
390+ allow ( File ) . to receive ( :exist? ) . and_call_original
391+ # Ensure default path is not checked when custom path is configured
392+ allow ( File ) . to receive ( :exist? )
393+ . with ( './config/initializers/inflections.rb' ) . and_return ( false )
394+ allow ( File ) . to receive ( :exist? )
395+ . with ( cop_config [ 'InflectorPath' ] ) . and_return ( true )
396+
397+ allow ( described_class ::ActiveSupportInflector ) . to receive ( :require )
398+ . with ( 'active_support/inflector' )
399+ stub_const ( 'ActiveSupport::Inflector' ,
400+ Module . new { def self . underscore ( _ ) ; end } )
401+
402+ allow ( described_class ::ActiveSupportInflector ) . to receive ( :require )
403+ . with ( cop_config [ 'InflectorPath' ] )
404+ allow ( ActiveSupport ::Inflector ) . to receive ( :underscore )
405+ . and_return ( '' )
406+ end
407+
408+ it 'reads the InflectorPath configuration correctly and does not ' \
409+ 'fall back to the default inflector path' , :aggregate_failures do
410+ expect_no_offenses ( <<~RUBY , 'http_client_spec.rb' )
411+ describe HTTPClient do; end
412+ RUBY
413+
414+ expect ( File ) . to have_received ( :exist? )
415+ . with ( '/custom/path/to/inflections.rb' )
416+ expect ( File ) . not_to have_received ( :exist? )
417+ . with ( './config/initializers/inflections.rb' )
418+ end
419+ end
420+ end
421+ # rubocop:enable RSpec/NestedGroups
284422end
0 commit comments