diff --git a/CHANGELOG.md b/CHANGELOG.md index 1139d48..555f207 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Fix a false positive for `FactoryBot/ConsistentParenthesesStyle` when using traits and omitting hash values. ([@thejonroberts]) +- Fix `FactoryBot/CreateList` to detect iterations over ranges. ([@ydakuka]) ## 2.26.1 (2024-06-12) @@ -117,3 +118,4 @@ [@walf443]: https://github.com/walf443 [@ybiquitous]: https://github.com/ybiquitous [@ydah]: https://github.com/ydah +[@ydakuka]: https://github.com/ydakuka diff --git a/lib/rubocop/cop/factory_bot/create_list.rb b/lib/rubocop/cop/factory_bot/create_list.rb index 1fc95ae..85188d4 100644 --- a/lib/rubocop/cop/factory_bot/create_list.rb +++ b/lib/rubocop/cop/factory_bot/create_list.rb @@ -108,6 +108,18 @@ class CreateList < ::RuboCop::Cop::Base # rubocop:disable Metrics/ClassLength (array #factory_call+) PATTERN + # @!method range_count(node) + def_node_matcher :range_count, <<~PATTERN + (block + (send + { + (begin (range $_ $_)) + (send nil? :Array (range $_ $_)) + } :map) + (args) + (send nil? :create sym ...)) + PATTERN + def on_array(node) return unless same_factory_calls_in_array?(node) return if node.values.size < 2 @@ -120,9 +132,34 @@ def on_array(node) end end - def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, Metrics/CyclomaticComplexity + def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler + if (range = range_count(node)) + process_range_based_offense(node, range) + else + process_repetition_offense(node) + end + end + + def process_range_based_offense(node, range) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + start_node, end_node = range + return if start_node.nil? || end_node.nil? + return if start_node.send_type? && end_node.send_type? + + range_node = node.receiver.children.last + start_value = extract_numeric_or_source_value(start_node) + end_value = extract_numeric_or_source_value(end_node) + + count = calculate_range_count(start_value, end_value, range_node.type) + + add_offense(node, message: MSG_CREATE_LIST) do |corrector| + factory_name = node.body.first_argument.source + corrector.replace(node, "create_list(#{factory_name}, #{count})") + end + end + + def process_repetition_offense(node) # rubocop:disable Metrics/CyclomaticComplexity return unless style == :create_list - return unless repeat_multiple_time?(node) + return unless repeats_multiple_times?(node) return if block_with_arg_and_used?(node) return unless node.body return if arguments_include_method_call?(node.body) @@ -148,7 +185,51 @@ def on_send(node) private - def repeat_multiple_time?(node) + def extract_numeric_or_source_value(end_node) + end_node.type?(:int, :float) ? end_node.value : end_node.source + end + + def calculate_range_count(start_value, end_value, type) # rubocop:disable Metrics/MethodLength + if start_value.is_a?(Numeric) && end_value.is_a?(Numeric) + return calculate_numeric_range_count(start_value, end_value, type) + end + + if end_value.is_a? Numeric + adjustment = "- #{start_value}" + count_expression_for_numeric_end(end_value, adjustment, type) + elsif start_value.is_a? Numeric + adjustment = + start_value.negative? ? "+ #{start_value.abs}" : "- #{start_value.floor}" # rubocop:disable Layout/LineLength + count_expression_for_numeric_start(end_value, adjustment, type) + end + end + + def count_expression_for_numeric_end(value, adjustment, range_type) + case range_type + when :irange + "(#{value.floor} #{adjustment} + 1)" + when :erange + "(#{value.ceil} #{adjustment})" + end + end + + def count_expression_for_numeric_start(value, adjustment, range_type) + case range_type + when :irange + "(#{value}.floor #{adjustment} + 1)" + when :erange + "(#{value}.ceil #{adjustment})" + end + end + + def calculate_numeric_range_count(start_val, end_val, range_type) + count = + end_val.send(range_type == :irange ? :floor : :ceil) - start_val + count += 1 if range_type == :irange + count + end + + def repeats_multiple_times?(node) return false unless (count = repeat_count(node)) count > 1 diff --git a/spec/rubocop/cop/factory_bot/create_list_spec.rb b/spec/rubocop/cop/factory_bot/create_list_spec.rb index ecc7de4..f5ecda3 100644 --- a/spec/rubocop/cop/factory_bot/create_list_spec.rb +++ b/spec/rubocop/cop/factory_bot/create_list_spec.rb @@ -268,6 +268,788 @@ end end + context 'with inclusive range' do + it 'registers and corrects an offense for a simple integer range' do + expect_offense(<<~RUBY) + (2..9).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 8) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when using Array() with a simple integer range' do + expect_offense(<<~RUBY) + Array(2..9).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 8) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a float upper bound' do + expect_offense(<<~RUBY) + (2..9.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 8) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative integer lower bound ' \ + 'and an positive integer upper bound' do + expect_offense(<<~RUBY) + (-5..7).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 13) + RUBY + end + + it 'does not register an offense ' \ + 'for an open-ended range with an infinite upper bound' do + expect_no_offenses(<<~RUBY) + (-5..).map { create :user } + RUBY + end + + it 'does not register an offense ' \ + 'for an open-ended range with an infinite lower bound' do + expect_no_offenses(<<~RUBY) + (..7).map { create :user } + RUBY + end + + it 'does not register an offense for a range with variable bounds' do + expect_no_offenses(<<~RUBY) + (n..m).map { create :user } + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and positive float upper bound' do + expect_offense(<<~RUBY) + n = 2 + (n..9.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = 2 + create_list(:user, (9 - n + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and positive integer upper bound' do + expect_offense(<<~RUBY) + n = 2 + (n..9).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = 2 + create_list(:user, (9 - n + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and a float positive upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n..7.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (7 - n + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and an positive integer upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n..7).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (7 - n + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and a negative float upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n..-2.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (-3 - n + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and an negative integer upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n..-2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (-2 - n + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is an instance variable' do + expect_offense(<<~RUBY) + (@instance_variable..2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - @instance_variable + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a class variable' do + expect_offense(<<~RUBY) + (@@class_variable..2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - @@class_variable + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a global variable' do + expect_offense(<<~RUBY) + ($global_variable..2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - $global_variable + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a constant' do + expect_offense(<<~RUBY) + (CONST..2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - CONST + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a namespaced constant' do + expect_offense(<<~RUBY) + (SomeModule::CONST..2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - SomeModule::CONST + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a cbase namespaced constant' do + expect_offense(<<~RUBY) + (::SomeModule::CONST..2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - ::SomeModule::CONST + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with an positive integer lower bound ' \ + 'and a positive float upper bound' do + expect_offense(<<~RUBY) + m = 9.99 + (2..m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 9.99 + create_list(:user, (m.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense for a range with integer bounds' do + expect_offense(<<~RUBY) + m = 9 + (2..m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 9 + create_list(:user, (m.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative integer lower bound ' \ + 'and a positive float upper bound' do + expect_offense(<<~RUBY) + m = 7.99 + (-5..m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 7.99 + create_list(:user, (m.floor + 5 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative integer lower bound ' \ + 'and a positive integer upper bound' do + expect_offense(<<~RUBY) + m = 7 + (-5..m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 7 + create_list(:user, (m.floor + 5 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative float lower bound ' \ + 'and a negative float upper bound' do + expect_offense(<<~RUBY) + m = -2.99 + (-5..m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = -2.99 + create_list(:user, (m.floor + 5 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with negative integer bounds' do + expect_offense(<<~RUBY) + m = -2 + (-5..m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = -2 + create_list(:user, (m.floor + 5 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is an instance variable' do + expect_offense(<<~RUBY) + (2..@instance_variable).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (@instance_variable.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a class variable' do + expect_offense(<<~RUBY) + (2..@@class_variable).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (@@class_variable.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a global variable' do + expect_offense(<<~RUBY) + (2..$global_variable).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, ($global_variable.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a constant' do + expect_offense(<<~RUBY) + (2..CONST).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (CONST.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a namespaced constant' do + expect_offense(<<~RUBY) + (2..SomeModule::CONST).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (SomeModule::CONST.floor - 2 + 1)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a cbase namespaced constant' do + expect_offense(<<~RUBY) + (2..::SomeModule::CONST).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (::SomeModule::CONST.floor - 2 + 1)) + RUBY + end + end + + context 'with exclusive range' do + it 'registers and corrects an offense for a simple integer range' do + expect_offense(<<~RUBY) + (2...9).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 7) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when using Array() with a simple integer range' do + expect_offense(<<~RUBY) + Array(2...9).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 7) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a float upper bound' do + expect_offense(<<~RUBY) + (2...9.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 8) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative integer lower bound ' \ + 'and an positive integer upper bound' do + expect_offense(<<~RUBY) + (-5...7).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, 12) + RUBY + end + + it 'does not register an offense ' \ + 'for an open-ended range with an infinite upper bound' do + expect_no_offenses(<<~RUBY) + (-5...).map { create :user } + RUBY + end + + it 'does not register an offense ' \ + 'for an open-ended range with an infinite lower bound' do + expect_no_offenses(<<~RUBY) + (...7).map { create :user } + RUBY + end + + it 'does not register an offense for a range with variable bounds' do + expect_no_offenses(<<~RUBY) + (n...m).map { create :user } + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and positive float upper bound' do + expect_offense(<<~RUBY) + n = 2 + (n...9.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = 2 + create_list(:user, (10 - n)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and positive integer upper bound' do + expect_offense(<<~RUBY) + n = 2 + (n...9).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = 2 + create_list(:user, (9 - n)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and a float positive upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n...7.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (8 - n)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and an positive integer upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n...7).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (7 - n)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and a negative float upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n...-2.99).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (-2 - n)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a variable lower bound ' \ + 'and an negative integer upper bound' do + expect_offense(<<~RUBY) + n = -5 + (n...-2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + n = -5 + create_list(:user, (-2 - n)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is an instance variable' do + expect_offense(<<~RUBY) + (@instance_variable...2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - @instance_variable)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a class variable' do + expect_offense(<<~RUBY) + (@@class_variable...2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - @@class_variable)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a global variable' do + expect_offense(<<~RUBY) + ($global_variable...2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - $global_variable)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a constant' do + expect_offense(<<~RUBY) + (CONST...2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - CONST)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a namespaced constant' do + expect_offense(<<~RUBY) + (SomeModule::CONST...2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - SomeModule::CONST)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the lower bound is a cbase namespaced constant' do + expect_offense(<<~RUBY) + (::SomeModule::CONST...2).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (2 - ::SomeModule::CONST)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with an positive integer lower bound ' \ + 'and a positive float upper bound' do + expect_offense(<<~RUBY) + m = 9.99 + (2...m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 9.99 + create_list(:user, (m.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense for a range with integer bounds' do + expect_offense(<<~RUBY) + m = 9 + (2...m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 9 + create_list(:user, (m.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative integer lower bound ' \ + 'and a positive float upper bound' do + expect_offense(<<~RUBY) + m = 7.99 + (-5...m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 7.99 + create_list(:user, (m.ceil + 5)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative integer lower bound ' \ + 'and a positive integer upper bound' do + expect_offense(<<~RUBY) + m = 7 + (-5...m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = 7 + create_list(:user, (m.ceil + 5)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with a negative float lower bound ' \ + 'and a negative float upper bound' do + expect_offense(<<~RUBY) + m = -2.99 + (-5...m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = -2.99 + create_list(:user, (m.ceil + 5)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'for a range with negative integer bounds' do + expect_offense(<<~RUBY) + m = -2 + (-5...m).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + m = -2 + create_list(:user, (m.ceil + 5)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is an instance variable' do + expect_offense(<<~RUBY) + (2...@instance_variable).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (@instance_variable.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a class variable' do + expect_offense(<<~RUBY) + (2...@@class_variable).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (@@class_variable.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a global variable' do + expect_offense(<<~RUBY) + (2...$global_variable).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, ($global_variable.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a constant' do + expect_offense(<<~RUBY) + (2...CONST).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (CONST.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a namespaced constant' do + expect_offense(<<~RUBY) + (2...SomeModule::CONST).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (SomeModule::CONST.ceil - 2)) + RUBY + end + + it 'registers and corrects an offense ' \ + 'when the upper bound is a cbase namespaced constant' do + expect_offense(<<~RUBY) + (2...::SomeModule::CONST).map { create :user } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer create_list. + RUBY + + expect_correction(<<~RUBY) + create_list(:user, (::SomeModule::CONST.ceil - 2)) + RUBY + end + end + context 'when ExplicitOnly is false' do let(:explicit_only) { false }