# frozen_string_literal: true

require 'test_helper'

class TestConflictingDirectory < LoaderTest
  def dir
    __dir__
  end

  def parent
    File.expand_path('..', dir)
  end

  def existing_loader
    @existing_loader ||= new_loader(setup: false)
  end

  def loader
    @loader ||= new_loader(setup: false)
  end

  def conflicting_directory_message(dir)
    require 'pp'
    "loader\n\n#{loader.pretty_inspect}\n\nwants to manage directory #{dir}," \
    " which is already managed by\n\n#{existing_loader.pretty_inspect}\n"
  end

  test 'raises if an existing loader manages the same root dir' do
    existing_loader.push_dir(dir)

    e = assert_raises(Zeitwerk::Error) { loader.push_dir(dir) }
    assert_equal conflicting_directory_message(dir), e.message
  end

  test 'raises if an existing loader manages a parent directory' do
    existing_loader.push_dir(parent)

    e = assert_raises(Zeitwerk::Error) { loader.push_dir(dir) }
    assert_equal conflicting_directory_message(dir), e.message
  end

  test 'raises if an existing loader manages a subdirectory' do
    existing_loader.push_dir(dir)

    e = assert_raises(Zeitwerk::Error) { loader.push_dir(parent) }
    assert_equal conflicting_directory_message(parent), e.message
  end

  test 'does not raise if an existing loader manages a directory with a matching prefix' do
    files = [['foo/x.rb', 'X = 1'], ['foobar/y.rb', 'Y = 1']]
    with_files(files) do
      existing_loader.push_dir('foo')
      assert loader.push_dir('foobar')
    end
  end

  test 'does not raise if an existing loader ignores the directory (dir)' do
    existing_loader.push_dir(parent)
    existing_loader.ignore(dir)
    assert loader.push_dir(dir)
  end

  test 'does not raise if a second existing loader ignores the directory (dir)' do
    # Ensure this loader is loaded
    existing_loader
    second_existing_loader = new_loader(setup: false)
    second_existing_loader.push_dir(parent)
    second_existing_loader.ignore(dir)

    assert loader.push_dir(dir)
  end

  test 'does not raise if an existing loader ignores the directory (glob pattern)' do
    existing_loader.push_dir(parent)
    existing_loader.ignore("#{parent}/*")
    assert loader.push_dir(dir)
  end

  test 'does not raise if the loader ignores a directory managed by an existing loader (dir)' do
    existing_loader.push_dir(dir)
    loader.ignore(dir)
    assert loader.push_dir(parent)
  end

  test 'does not raise if the loader ignores a directory managed by an existing loader (glob pattern)' do
    existing_loader.push_dir(dir)
    loader.ignore("#{parent}/*")
    assert loader.push_dir(parent)
  end

  test 'raises if an existing loader ignores a directory with a matching prefix' do
    files = [['foo/x.rb', 'X = 1'], ['foobar/y.rb', 'Y = 1']]
    with_files(files) do
      ignored         = File.expand_path('foo')
      conflicting_dir = File.expand_path('foobar')

      existing_loader.push_dir('.')
      existing_loader.ignore(ignored)

      e = assert_raises(Zeitwerk::Error) { loader.push_dir(conflicting_dir) }
      assert_equal conflicting_directory_message(conflicting_dir), e.message
    end
  end
end
