package com.atlassian.bitbucket.mesh.util;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;

import static org.junit.Assert.*;

public class SortedShaSetTest {

    @Test
    public void testAddGrowsCapacityAsNeeded() {
        SortedShaSet shas = new SortedShaSet();
        SortedSet<String> set = new TreeSet<>();
        for (int i = 0; i < 20000; ++i) {
            String hash = StringUtils.leftPad(Integer.toString(i), 10, '0');
            shas.add(hash);
            set.add(hash);
        }

        assertEquals(20000, shas.size());
        assertEquals(20000, set.size());
        Iterator<String> it = set.iterator();
        for (int i = 0; i < shas.size(); ++i) {
            assertTrue(it.hasNext());
            assertEquals(it.next(), shas.get(i));
        }
    }

    @Test
    public void testAdd() {
        SortedShaSet shas = new SortedShaSet();
        assertTrue(shas.add("abcdef"));

        assertFalse(shas.add("abc"));
        assertFalse(shas.add("abcdef"));
        assertFalse(shas.add("abcdefgh"));

        // postfix should not match
        assertTrue(shas.add("bcdef"));
    }

    @Test
    public void testContains() {
        SortedShaSet shas = new SortedShaSet();
        shas.add("abcdef");

        assertFalse(shas.contains("123456"));
        assertFalse(shas.contains("bcdef"));
        assertTrue(shas.contains("abcd"));
        assertTrue(shas.contains("abcdef"));
        assertTrue(shas.contains("abcdefgh"));

        // postfix should not match
        assertFalse(shas.contains("bcdef"));
    }

    @Test
    public void testEqualsAndHashCode() {
        SortedShaSet shas1 = new SortedShaSet();
        SortedShaSet shas2 = new SortedShaSet();
        SortedShaSet shas3 = new SortedShaSet();

        assertTrue(shas1.equals(shas2));
        assertTrue(shas2.equals(shas1));
        // two objects that are equal should have the same hashcode
        assertEquals(shas1.hashCode(), shas2.hashCode());

        shas1.add("aabbccddee");
        assertFalse(shas1.equals(shas2));
        assertFalse(shas2.equals(shas1));

        shas2.add("aabbccddeeff");
        shas3.add("a");
        assertTrue(shas1.equals(shas1));
        assertTrue(shas1.equals(shas2));
        assertTrue(shas1.equals(shas3));
        assertTrue(shas2.equals(shas1));
        assertTrue(shas2.equals(shas2));
        assertTrue(shas2.equals(shas3));
        assertTrue(shas3.equals(shas1));
        assertTrue(shas3.equals(shas2));
        assertTrue(shas3.equals(shas3));
        assertEquals(shas1.hashCode(), shas2.hashCode());
        assertEquals(shas1.hashCode(), shas3.hashCode());
        assertEquals(shas2.hashCode(), shas3.hashCode());
    }

    @Test
    public void testGet() {
        SortedShaSet shas = new SortedShaSet();

        assertEquals(0, shas.size());
        shas.add("hash3");
        shas.add("hash1");
        shas.add("hash2");

        assertEquals(3, shas.size());
        assertEquals("hash1", shas.get(0));
        assertEquals("hash2", shas.get(1));
        assertEquals("hash3", shas.get(2));
    }

    @Test(expected = IndexOutOfBoundsException.class)
    public void testGetNegativeIndex() {
        new SortedShaSet().get(-1);
    }

    @Test(expected = IndexOutOfBoundsException.class)
    public void testGetOutOfBounds() {
        new SortedShaSet().get(1);
    }

    @Test
    public void testIndexOf() {
        SortedShaSet shas = new SortedShaSet();
        shas.add("abcdef");

        assertEquals(-1, shas.indexOf("123456"));
        assertEquals(0, shas.indexOf("abcd"));
        assertEquals(0, shas.indexOf("abcdef"));
        assertEquals(0, shas.indexOf("abcdefgh"));

        // postfix should not match
        assertEquals(-1, shas.indexOf("bcdef"));
    }

    @Test
    public void testRemove() {
        SortedShaSet shas = new SortedShaSet();

        shas.add("abcdef");
        assertTrue(shas.remove("abcd"));

        shas.add("abcdef");
        assertTrue(shas.remove("abcdef"));

        shas.add("abcdef");
        assertTrue(shas.remove("abcdefgh"));

        // postfix should not match
        shas.add("abcdef");
        assertFalse(shas.remove("bcdef"));
    }
}