require "test_helper"

# Shared assertions for predicate + black_hole combinations
module PredicateBlackHoleAssertions
  def test_predicates_return_false
    refute_predicate @null, :too_much_coffee?
  end

  def test_other_methods_return_self
    assert_returns_self @null, :foobar
  end
end

class PredicateTest < NaughtTestCase
  def setup
    _, @null = build_null { |b| b.predicates_return false }
  end

  def test_responds_to_predicate_style_methods_with_false
    refute_predicate @null, :too_much_coffee?
  end

  def test_responds_to_other_methods_with_nil
    assert_nil @null.foobar
  end

  def test_reports_responding_to_predicate_methods
    assert_respond_to @null, :too_much_coffee?
  end
end

class PredicateBlackHoleTest < NaughtTestCase
  include PredicateBlackHoleAssertions

  def setup
    _, @null = build_null { |b|
      b.black_hole
      b.predicates_return false
    }
  end
end

class PredicateBlackHoleReverseOrderTest < NaughtTestCase
  include PredicateBlackHoleAssertions

  def setup
    _, @null = build_null { |b|
      b.predicates_return false
      b.black_hole
    }
  end
end

class PredicateMimicTest < NaughtTestCase
  def setup
    @null_class = build_null_class { |b|
      b.mimic NaughtTestFixtures::Coffee
      b.predicates_return false
    }
    @null = @null_class.new
  end

  def test_mimicked_predicate_returns_false
    refute_predicate @null, :black?
  end

  def test_other_mimicked_methods_return_nil
    assert_nil @null.origin
  end

  def test_does_not_respond_to_undefined_methods
    refute_respond_to @null, :leaf_variety
  end

  def test_raises_for_undefined_methods
    assert_raises(NoMethodError) { @null.leaf_variety }
  end
end

# Test for GitHub issue #60: predicates_return(false) breaks NullObject coercion
# https://github.com/avdi/naught/issues/60
class PredicateCoercionTest < NaughtTestCase
  def setup
    @null_class = Naught.build { |b| b.predicates_return false }
    @null_class.define_method(:coerce) { |other| [other, 1] }
    @null = @null_class.new
  end

  def test_coerce_works_with_predicates_return
    assert_equal [5, 1], @null.coerce(5)
  end

  def test_responds_to_coerce
    assert_respond_to @null, :coerce
  end

  def test_division_coercion_works
    assert_equal 1, 1 / @null
  end

  def test_multiplication_coercion_works
    assert_equal 5, 5 * @null
  end

  def test_addition_coercion_works
    assert_equal 4, 3 + @null
  end

  def test_subtraction_coercion_works
    assert_equal 6, 7 - @null
  end

  def test_predicates_still_return_false
    refute_predicate @null, :valid?
  end
end
