# frozen_string_literal: true

require 'test_helper'
require 'set'

class TestIgnore < LoaderTest
  def this_dir
    @this_dir ||= __dir__
  end

  def this_file
    @this_file ||= File.expand_path(__FILE__, this_dir)
  end

  def ascendant
    @dir_up ||= File.expand_path("#{this_dir}/../..")
  end

  test 'ignored root directories are ignored' do
    files = [['x.rb', 'X = true']]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('.')
      loader.setup

      assert !Object.autoload?(:X)
      assert_raises(NameError) { ::X }
    end
  end

  test 'ignored root directories are ignored, but nested ones are not' do
    files = [['x.rb', 'X = true'], ['nested/y.rb', 'Y = true']]
    with_files(files) do
      loader.push_dir('.')
      loader.push_dir('nested')
      loader.ignore('.')
      loader.setup

      assert !Object.autoload?(:X)
      assert_raises(NameError) { ::X }
      assert Y
    end
  end

  test 'ignored files are ignored' do
    files = [
      ['x.rb', 'X = true'],
      ['y.rb', 'Y = true']
    ]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('y.rb')
      loader.setup

      assert Object.autoload?(:X)
      assert !Object.autoload?(:Y)

      assert ::X
      assert_raises(NameError) { ::Y }
    end
  end

  test 'ignored directories are ignored' do
    files = [
      ['x.rb', 'X = true'],
      ['m/a.rb', 'M::A = true'],
      ['m/b.rb', 'M::B = true'],
      ['m/c.rb', 'M::C = true']
    ]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('m')
      loader.setup

      assert Object.autoload?(:X)
      assert !Object.autoload?(:M)

      assert ::X
      assert_raises(NameError) { ::M }
    end
  end

  test 'ignored files are not eager loaded' do
    files = [
      ['x.rb', 'X = true'],
      ['y.rb', 'Y = true']
    ]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('y.rb')
      loader.setup
      loader.eager_load

      assert ::X
      assert_raises(NameError) { ::Y }
    end
  end

  test 'ignored directories are not eager loaded' do
    files = [
      ['x.rb', 'X = true'],
      ['m/a.rb', 'M::A = true'],
      ['m/b.rb', 'M::B = true'],
      ['m/c.rb', 'M::C = true']
    ]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('m')
      loader.setup
      loader.eager_load

      assert ::X
      assert_raises(NameError) { ::M }
    end
  end

  test 'supports several arguments' do
    a = "#{Dir.pwd}/a.rb"
    b = "#{Dir.pwd}/b.rb"
    loader.ignore(a, b)
    assert_equal [a, b].to_set, loader.send(:ignored_glob_patterns)
  end

  test 'supports an array' do
    a = "#{Dir.pwd}/a.rb"
    b = "#{Dir.pwd}/b.rb"
    loader.ignore([a, b])
    assert_equal [a, b].to_set, loader.send(:ignored_glob_patterns)
  end

  test 'supports glob patterns' do
    files = [
      ['admin/user.rb', 'class Admin::User; end'],
      ['admin/user_test.rb', 'class Admin::UserTest < Minitest::Test; end']
    ]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('**/*_test.rb')
      loader.setup

      assert Admin::User
      assert_raises(NameError) { Admin::UserTest }
    end
  end

  test 'ignored paths are recomputed on reload' do
    files = [
      ['user.rb', 'class User; end'],
      ['user_test.rb', 'class UserTest < Minitest::Test; end'],
    ]
    with_files(files) do
      loader.push_dir('.')
      loader.ignore('*_test.rb')
      loader.setup

      assert User
      assert_raises(NameError) { UserTest }

      File.write('post.rb', 'class Post; end')
      File.write('post_test.rb', 'class PostTest < Minitest::Test; end')

      loader.reload

      assert Post
      assert_raises(NameError) { PostTest }
    end
  end

  test 'returns true if a directory is ignored as is' do
    loader.ignore(this_dir)
    assert loader.__ignores?(this_dir)
  end

  test 'returns true if a file is ignored as is' do
    loader.ignore(this_file)
    assert loader.__ignores?(this_file)
  end

  test 'returns true for a descendant of an ignored directory' do
    loader.ignore(ascendant)
    assert loader.__ignores?(this_dir)
  end

  test 'returns true for a file in a descendant of an ignored directory' do
    loader.ignore(ascendant)
    assert loader.__ignores?(this_file)
  end

  test 'returns false for the directory of an ignored file' do
    loader.ignore(this_file)
    assert !loader.__ignores?(this_dir)
  end

  test 'returns false for an ascendant directory of an ignored directory' do
    loader.ignore(this_dir)
    assert !loader.__ignores?(ascendant)
  end

  test 'returns false if nothing is ignored' do
    assert !loader.__ignores?(this_dir)
    assert !loader.__ignores?(this_file)
  end
end
