package com.atlassian.bitbucket.mesh.partition;

import com.atlassian.bitbucket.mesh.junit.LogListener;
import com.atlassian.bitbucket.mesh.platform.DefaultOperatingSystemService;
import org.junit.Rule;
import org.junit.Test;

import java.util.TreeSet;

import static org.junit.Assert.*;

public class PartitionTest {

    @Rule
    public final LogListener logListener = new LogListener(DefaultOperatingSystemService.class);

    @Test
    public void testThrowExceptionForShortName() throws Exception {
        InvalidPartitionNameException ex = assertThrows(InvalidPartitionNameException.class, () -> {
            new Partition("001");
        });
    }

    @Test
    public void testThrowExceptionForInvalidCharacters() throws Exception {
        InvalidPartitionNameException ex = assertThrows(InvalidPartitionNameException.class, () -> {
            new Partition("000z");
        });
    }

    @Test
    public void testThrowExceptionForLongName() throws Exception {
        InvalidPartitionNameException ex = assertThrows(InvalidPartitionNameException.class, () -> {
            new Partition("1234567812345678");
        });
    }

    @Test
    public void testCanParse60BitPartitionName() throws Exception {
        Partition p = new Partition("fffffffffffffff");

        assertNotNull(p);
        assertEquals("fffffffffffffff", p.getHex());
    }

    @Test
    public void testCanParseShortPartitionName() throws Exception {
        Partition p = new Partition("ffff");

        assertNotNull(p);
        assertEquals("ffff", p.getHex());
    }

    @Test
    public void testCompareToSortsCorrectly() throws Exception {
        TreeSet<Partition> ts = new TreeSet<>();

        // Add to the tree "out of order" to make sure sorting is
        // exercised.
        ts.add(new Partition("f00000000000000"));
        ts.add(new Partition("5000"));
        ts.add(new Partition("fffffffffffffff"));
        ts.add(new Partition("0001"));
        ts.add(new Partition("ffffffff"));
        ts.add(new Partition("00000000000000f"));
        ts.add(new Partition("ffff"));
        ts.add(new Partition("f0000000"));

        assertEquals(8, ts.size());
        Partition[] pArray = ts.toArray(new Partition[ts.size()]);

        assertEquals("0001", pArray[0].getHex());
        assertEquals("00000000000000f", pArray[1].getHex());
        assertEquals("5000", pArray[2].getHex());
        assertEquals("ffff", pArray[3].getHex());
        assertEquals("f0000000", pArray[4].getHex());
        assertEquals("ffffffff", pArray[5].getHex());
        assertEquals("f00000000000000", pArray[6].getHex());
        assertEquals("fffffffffffffff", pArray[7].getHex());
    }

    @Test
    public void testEqualsMatches() throws Exception {
        Partition p1 = new Partition("0001");
        Partition p2 = new Partition("0001");
        assertTrue(p1.equals(p2));

        p1 = new Partition("ffffffff");
        p2 = new Partition("ffffffff");
        assertTrue(p1.equals(p2));

        p1 = new Partition("fffffffffffffff");
        p2 = new Partition("fffffffffffffff");
        assertTrue(p1.equals(p2));
    }

    @Test
    public void testEqualsDoesNotMatch() throws Exception {
        Partition p1 = new Partition("0001");
        Partition p2 = new Partition("0002");
        assertFalse(p1.equals(p2));

        p1 = new Partition("ffffffff");
        p2 = new Partition("fffffff0");
        assertFalse(p1.equals(p2));

        p1 = new Partition("fffffffffffffff");
        p2 = new Partition("ffffffffffffff0");
        assertFalse(p1.equals(p2));
    }

    @Test
    public void testHashCode() throws Exception {
        Partition p = new Partition("ffff");
        assertNotNull(p);
        assertEquals(65535, p.hashCode());

        p = new Partition("ffffffff");
        assertNotNull(p);
        assertEquals(-1, p.hashCode());

        p = new Partition("fffffffffffffff");
        assertNotNull(p);
        assertEquals(-268435456, p.hashCode());
    }
}
