Module: RSpec::Armour::Checker

Defined in:
lib/rspec/armour/checker.rb

Constant Summary collapse

RESTRICTED_CLASS_METHODS =
%i[
  find find_by find_by! where all first last count sum average minimum
  maximum pluck pick exists? create create! find_or_create_by
  find_or_create_by! find_or_initialize_by update update! destroy_all
  delete_all delete_by destroy_by first_or_create first_or_create!
  first_or_initialize
].freeze
RESTRICTED_INSTANCE_METHODS =
%i[
  save save! update update! update_attribute update_columns update_column
  destroy destroy! delete delete! touch reload increment! decrement!
  toggle!
].freeze
DISABLED_KEY =
:rspec_armour_disabled

Class Method Summary collapse

Class Method Details

.association_method_on_class?(klass, method_name) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/rspec/armour/checker.rb', line 74

def self.association_method_on_class?(klass, method_name)
  return false unless klass.respond_to?(:reflections)

  reflections = klass.reflections
  reflections.any? do |name, _reflection|
    singular_name = name.to_s.singularize
    [
      name.to_sym,
      :"#{name}=",
      :"#{singular_name}_ids",
      :"#{singular_name}_ids=",
    ].include?(method_name)
  end
end

.disable!Object



93
94
95
96
97
98
99
# File 'lib/rspec/armour/checker.rb', line 93

def self.disable!
  previous = Thread.current[DISABLED_KEY]
  Thread.current[DISABLED_KEY] = true
  yield
ensure
  Thread.current[DISABLED_KEY] = previous
end

.disabled?Boolean

Returns:

  • (Boolean)


89
90
91
# File 'lib/rspec/armour/checker.rb', line 89

def self.disabled?
  Thread.current[DISABLED_KEY]
end

.resolve_double_info(target) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rspec/armour/checker.rb', line 50

def self.resolve_double_info(target)
  ref = target.instance_variable_get(:@doubled_module)
  return [false, nil] unless ref.respond_to?(:target)

  underlying_target = ref.target
  case target
  when ::RSpec::Mocks::InstanceVerifyingDouble
    [false, underlying_target]
  when ::RSpec::Mocks::ClassVerifyingDouble
    [true, underlying_target]
  when ::RSpec::Mocks::ObjectVerifyingDouble
    is_class = underlying_target.is_a?(Class)
    [is_class, is_class ? underlying_target : underlying_target.class]
  else
    [false, nil]
  end
end

.resolve_target_info(target) ⇒ Object



37
38
39
40
41
42
43
44
# File 'lib/rspec/armour/checker.rb', line 37

def self.resolve_target_info(target)
  if test_double?(target)
    resolve_double_info(target)
  else
    is_class = target.is_a?(Class)
    [is_class, is_class ? target : target.class]
  end
end

.restricted?(target, method_name) ⇒ Boolean

Returns:

  • (Boolean)


25
26
27
28
29
30
31
32
33
34
35
# File 'lib/rspec/armour/checker.rb', line 25

def self.restricted?(target, method_name)
  return false if disabled?

  method_sym = method_name.to_sym
  is_class, klass = resolve_target_info(target)

  return false unless klass.is_a?(Class) && klass < ::ActiveRecord::Base

  restricted_by_list?(is_class,
                      method_sym) || association_method_on_class?(klass, method_sym)
end

.restricted_by_list?(is_class, method_sym) ⇒ Boolean

Returns:

  • (Boolean)


68
69
70
71
72
# File 'lib/rspec/armour/checker.rb', line 68

def self.restricted_by_list?(is_class, method_sym)
  return true if RESTRICTED_INSTANCE_METHODS.include?(method_sym)

  is_class && RESTRICTED_CLASS_METHODS.include?(method_sym)
end

.test_double?(target) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/rspec/armour/checker.rb', line 46

def self.test_double?(target)
  defined?(::RSpec::Mocks::TestDouble) && target.is_a?(::RSpec::Mocks::TestDouble)
end