# frozen_string_literal: true

require 'test_helper'

class TestCref < LoaderTest
  def klass
    self.class
  end

  def new_cref(mod = klass, cname = :Foo)
    Zeitwerk::Cref.new(mod, cname)
  end

  test '#cname' do
    assert_equal :Foo, new_cref.cname
  end

  test '#path for Object' do
    assert_equal 'Foo', new_cref(Object).path
  end

  test '#path for another namespace' do
    assert_equal "#{self.class}::Foo", new_cref.path
  end

  test '#to_s is #path' do
    assert_equal Zeitwerk::Cref.instance_method(:to_s), Zeitwerk::Cref.instance_method(:path)
  end

  test '#autoload?' do
    on_teardown { remove_const :Foo, from: klass }

    klass.autoload(:Foo, '/foo')
    assert_equal '/foo', new_cref.autoload?
  end

  test '#autoload' do
    on_teardown { remove_const :Foo, from: klass }

    new_cref.autoload('/foo')
    assert_equal '/foo', klass.autoload?(:Foo)
  end

  test '#defined? finds a constant defined in mod' do
    on_teardown { remove_const :Foo, from: klass }

    klass.const_set(:Foo, 1)
    assert new_cref.defined?
  end

  test '#defined? ignores the ancestors' do
    cname = :TMP_DIR
    assert klass.superclass.const_defined?(cname) # precondition
    assert !new_cref(klass, cname).defined?
  end

  test '#set' do
    on_teardown { remove_const :Foo, from: klass }

    assert_equal 1, new_cref.set(1)
    assert_equal 1, klass::Foo
  end

  test '#get' do
    on_teardown { remove_const :Foo, from: klass }

    klass.const_set(:Foo, 1)
    assert_equal 1, new_cref.get
  end

  test '#get with unknown cname' do
    assert_raises(NameError) { new_cref.get }
  end

  test '#remove' do
    cref = new_cref

    cref.set(1)
    assert cref.defined? # precondition

    cref.remove
    assert !cref.defined?
  end

  test '#remove with unknown cname' do
    assert_raises(NameError) { new_cref.remove }
  end

  test '#location returns file:line if the constant exists' do
    expected_location = Zeitwerk.const_source_location(:Loader).join(':')
    assert_equal expected_location, new_cref(Zeitwerk, :Loader).location
  end

  test '#location returns nil if the constant does not exist' do
    assert_nil new_cref(Object, :NonExistent).location
  end

  test '#location returns nil if the constant is defined but an empty array is returned' do
    assert_nil new_cref(Object, :Object).location
  end
end
