require 'test_helper'

class ValidateUniquenessOfMatcherTest < ShouldaDataMapperTest # :nodoc:

  context "a unique attribute" do
    setup do
      @model = define_model :example do
        property :attr, String
        property :other, Integer
        validates_uniqueness_of :attr
      end.new
      recreate_database
    end

    context "with an existing value" do
      setup do
        @existing = Example.create!(:attr => 'value', :other => 1)
      end

      should "require a unique value for that attribute" do
        assert_accepts validate_uniqueness_of(:attr), @model
      end

      should "pass when the subject is an existing record" do
        assert_accepts validate_uniqueness_of(:attr), @existing
      end

      should "fail when a scope is specified" do
        assert_rejects validate_uniqueness_of(:attr).scoped_to(:other), @model
      end
    end

    context "without an existing value" do
      setup do
        assert_nil Example.first
        @matcher = validate_uniqueness_of(:attr)
      end

      should "fail to require a unique value" do
        assert_rejects @matcher, @model
      end

      should "alert the tester that an existing value is not present" do
        @matcher.matches?(@model)
        assert @matcher.negative_failure_message =~ /^Can't find first .*/
      end
    end
  end

  context "a unique attribute and an existing value" do
    setup do
      @model = define_model :example do
        property :attr, String
        validates_uniqueness_of :attr
      end.new
      recreate_database
      Example.create! :attr => "value"
    end

    should "pass when checking the default message" do
      assert_accepts validate_uniqueness_of(:attr), @model
    end
  end

  context "a unique attribute with a custom error and an existing value" do
    setup do
      @model = define_model :example do
        property :attr, String
        validates_uniqueness_of :attr, :message => 'Bad value'
      end.new
      recreate_database
      Example.create! :attr => "value"
    end

    should "fail when checking the default message" do
      assert_rejects validate_uniqueness_of(:attr), @model
    end

    should "fail when checking a message that doesn't match" do
      assert_rejects validate_uniqueness_of(:attr).with_message(/abc/i), @model
    end

    should "pass when checking a message that matches" do
      assert_accepts validate_uniqueness_of(:attr).with_message("Bad value"), @model
    end
  end

  context "a scoped unique attribute with an existing value" do
    setup do
      @model = define_model :example do
        property :attr, String
        property :scope1, Integer
        property :scope2, Integer
        validates_uniqueness_of :attr, :scope => [:scope1, :scope2]
      end.new
      recreate_database
      @existing = Example.create!(:attr => 'value', :scope1 => 1, :scope2 => 2)
    end

    should "pass when the correct scope is specified" do
      assert_accepts validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2), @model
    end

    should "pass when the subject is an existing record" do
      assert_accepts validate_uniqueness_of(:attr).scoped_to(:scope1, :scope2), @existing
    end

    should "fail when a different scope is specified" do
      assert_rejects validate_uniqueness_of(:attr).scoped_to(:scope1), @model
    end

    should "fail when no scope is specified" do
      assert_rejects validate_uniqueness_of(:attr), @model
    end

    should "fail when a non-existent attribute is specified as a scope" do
      assert_rejects validate_uniqueness_of(:attr).scoped_to(:fake), @model
    end
  end

  context "a non-unique attribute with an existing value" do
    setup do
      @model = define_model :example do
        property :attr, String
      end.new
      recreate_database
      Example.create!(:attr => 'value')
    end

    should "not require a unique value for that attribute" do
      assert_rejects validate_uniqueness_of(:attr), @model
    end
  end

  context "a case sensitive unique attribute with an existing value" do
    setup do
      @model = define_model :example do
        property :attr, String
        validates_uniqueness_of :attr, :case_sensitive => true
      end.new
      recreate_database
      Example.create!(:attr => 'value')
    end

    should "not require a unique, case-insensitive value for that attribute" do
      assert_rejects validate_uniqueness_of(:attr).case_insensitive, @model
    end

    should "require a unique, case-sensitive value for that attribute" do
      assert_accepts validate_uniqueness_of(:attr), @model
    end
  end

  context "a case sensitive unique String attribute with an existing value" do
    setup do
      @model = define_model :example do
        property :attr, String
        validates_uniqueness_of :attr, :case_sensitive => true
      end.new
      recreate_database
      Example.create!(:attr => 'value')
    end

    should "require a unique, case-insensitive value for that attribute" do
      assert_rejects validate_uniqueness_of(:attr).case_insensitive, @model
    end

    should "require a unique, case-sensitive value for that attribute" do
      assert_accepts validate_uniqueness_of(:attr), @model
    end
  end

end
