package com.atlassian.bitbucket.validation;

import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import javax.validation.ConstraintValidatorContext;
import java.util.Map;

import static org.junit.Assert.assertEquals;

@RunWith(MockitoJUnitRunner.class)
public class IntegerValidatorTest {

    private static final Map<Object, Boolean> TESTS = ImmutableMap.<Object, Boolean>builder()
            .put("abc", false)
            .put("0", true)
            .put((byte) 0, true)
            .put((short) 0, true)
            .put(0, true)
            .put(0L, true)
            .put("1", true)
            .put((byte) 1, true)
            .put((short) 1, true)
            .put(1, true)
            .put(1L, true)
            .put("-1", false)
            .put((byte) -1, false)
            .put((short) -1, false)
            .put(-1, false)
            .put(-1L, false)
            .put(Integer.toString(Integer.MAX_VALUE), true)
            .put(Integer.toString(Integer.MAX_VALUE) + '1', false)
            .put(Integer.MAX_VALUE - 1, true)
            .put(Integer.MAX_VALUE, true)
            .put(((long) Integer.MAX_VALUE) + 1, false)
            .put(Long.MAX_VALUE, false)
            .put(3.14159F, false)
            .put(3.14159, false)
            .put("3.14159", false)
            .put(3.5F, false)
            .put(3.5, false)
            .put("3.5", false)
            .put(3.0F, false)
            .put(3.0, false)
            .put("3.0", false)
            .build();

    private static final Map<Object, Boolean> TESTS_WHEN_ALLOWING_NEGATIVES = ImmutableMap.<Object, Boolean>builder()
            .put("abc", false)
            .put(0, true)
            .put(1, true)
            .put((byte) -1, true)
            .put((short) -1, true)
            .put(-1, true)
            .put(-1L, true)
            .put(Long.MAX_VALUE, false)
            .put(-3.5F, false)
            .put(-3.5, false)
            .put("-3.5", false)
            .put(-3.0F, false)
            .put(-3.0, false)
            .put("-3.0", false)
            .build();

    @Mock
    private ConstraintValidatorContext context;

    private final IntegerValidator validator = new IntegerValidator();

    @Test
    public void testValidation() throws Exception {
        testValidations(false, TESTS);
    }

    @Test
    public void testValidationForNull() throws Exception {
        testValidation(true, null);
    }

    @Test
    public void testValidationForNegatives() throws Exception {
        testValidations(true, TESTS_WHEN_ALLOWING_NEGATIVES);
    }

    private void testValidations(boolean allowNegative, Map<Object, Boolean> tests) {
        validator.allowNegative = allowNegative;
        for (Map.Entry<Object, Boolean> test : tests.entrySet()) {
            testValidation(test.getValue(), test.getKey());
        }
    }

    private void testValidation(boolean expected, Object value) {
        assertEquals("Unexpected result for " + value, expected, validator.isValid(value, context));
    }

}
