Thursday, June 04, 2026 1:46:29 AM
> test_attr_predicate.rb
# frozen_string_literal: true

require "test_helper"

class AttrPredicateMock
  attr_predicate :some_variable

  def initialize(value)
    @some_variable = value
  end
end

class TestModuleAttrPredicate < Minitest::Test
  def test_defines_the_predicate
    object = AttrPredicateMock.new(42)

    assert_equal(42, object.instance_variable_get(:@some_variable))
    assert(object.some_variable?)
  end

  def test_it_works_with_structs
    klass = Struct.new(:foo)
    klass.attr_predicate(:foo)

    object = klass.new(foo: 42)

    assert_equal(42, object.foo)
    assert(object.foo?)
  end

  def test_it_works_with_false
    klass = Data.define(:foo)
    klass.attr_predicate(:foo)

    object = klass.new(foo: false)

    assert_equal(false, object.foo)
    refute(object.foo?)
  end

  def test_it_raises_on_method_defined
    klass = Data.define(:foo) do
      def foo?
        puts "foo"
      end
    end

    assert_raises(ArgumentError) { klass.attr_predicate(:foo) }
  end

  def test_from_with_ivar_source
    klass = Class.new do
      attr_accessor :started_at
      attr_predicate :started, from: :@started_at
    end

    object = klass.new
    refute(object.started?)

    object.started_at = Time.now
    assert(object.started?)
  end

  def test_from_with_method_source
    klass = Class.new do
      attr_accessor :error_messages
      attr_predicate :errored, from: :error_messages
    end

    object = klass.new
    refute(object.errored?)

    object.error_messages = ["Something went wrong"]
    assert(object.errored?)
  end

  def test_from_with_undefined_ivar_returns_false
    klass = Class.new do
      attr_predicate :started, from: :@started_at
    end

    object = klass.new
    refute(object.started?)
  end

  def test_from_with_missing_method_raises_error
    klass = Class.new do
      attr_predicate :errored, from: :error_messages
    end

    object = klass.new
    assert_raises(NoMethodError) { object.errored? }
  end

  def test_from_with_multiple_attributes_raises_error
    klass = Class.new

    error = assert_raises(ArgumentError) do
      klass.attr_predicate(:started, :finished, from: :@started_at)
    end

    assert_match(/cannot use from: option with multiple attributes/i, error.message)
  end

  def test_private_option
    klass = Class.new do
      attr_accessor :verified
      attr_predicate :verified, private: true
    end

    object = klass.new
    object.verified = true

    refute(object.respond_to?(:verified?))
    assert(object.respond_to?(:verified?, true))
    assert(object.send(:verified?))
  end

  def test_private_with_from
    klass = Class.new do
      attr_accessor :verified_at
      attr_predicate :verified, from: :@verified_at, private: true
    end

    object = klass.new
    object.verified_at = Time.now

    refute(object.respond_to?(:verified?))
    assert(object.send(:verified?))
  end

  def test_empty_array_returns_false
    klass = Class.new do
      attr_accessor :errors
      attr_predicate :errors
    end

    object = klass.new
    object.errors = []

    refute(object.errors?)
  end

  def test_non_empty_array_returns_true
    klass = Class.new do
      attr_accessor :errors
      attr_predicate :errors
    end

    object = klass.new
    object.errors = ["something went wrong"]

    assert(object.errors?)
  end

  def test_empty_hash_returns_false
    klass = Class.new do
      attr_accessor :metadata
      attr_predicate :metadata
    end

    object = klass.new
    object.metadata = {}

    refute(object.metadata?)
  end

  def test_non_empty_hash_returns_true
    klass = Class.new do
      attr_accessor :metadata
      attr_predicate :metadata
    end

    object = klass.new
    object.metadata = {key: "value"}

    assert(object.metadata?)
  end

  def test_empty_string_returns_false
    klass = Class.new do
      attr_accessor :name
      attr_predicate :name
    end

    object = klass.new
    object.name = ""

    refute(object.name?)
  end

  def test_non_empty_string_returns_true
    klass = Class.new do
      attr_accessor :name
      attr_predicate :name
    end

    object = klass.new
    object.name = "Alice"

    assert(object.name?)
  end
end
All opinions represented herein are my own
- © 2024 - 2026 itsthedevman
- build 4294fb2