package com.atlassian.bitbucket.mesh.coordination;

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

import static org.junit.Assert.assertEquals;

public class LamportClockTest {

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

    @Test
    public void testOnReceivedExceedsMaxLong() {
        LamportClock clock = new LamportClock(Long.MAX_VALUE);
        assertEquals(0L, clock.onReceived(60626374268L));
        logListener.assertWarn("Clock overflow detected");
    }

    @Test
    public void testOnReceivedWithNegativeRemoteTimestamp() {
        LamportClock clock = new LamportClock(65L);
        assertEquals(66L, clock.onReceived(-8L));
        assertEquals(66L, clock.get());
    }

    @Test
    public void testOnReceivedWithNewerRemoteTimestamp() {
        LamportClock clock = new LamportClock(65L);
        assertEquals(99L, clock.onReceived(98L));
        assertEquals(99L, clock.get());
    }

    @Test
    public void testOnReceivedWithOlderRemoteTimestamp() {
        LamportClock clock = new LamportClock(65L);
        assertEquals(66L, clock.onReceived(60L));
        assertEquals(66L, clock.get());
    }

    @Test
    public void testOnReceivedWithSameRemoteTimestamp() {
        LamportClock clock = new LamportClock(65L);
        assertEquals(66L, clock.onReceived(65L));
        assertEquals(66L, clock.get());
    }

    @Test
    public void testTick() {
        LamportClock clock = new LamportClock(100L);
        for (int i = 1; i < 100; ++i) {
            long expected = 100L + i;
            assertEquals(expected, clock.tick());
            assertEquals(expected, clock.get());
        }
    }

    @Test
    public void testTickExceedsMaxLong() {
        LamportClock clock = new LamportClock(Long.MAX_VALUE);
        assertEquals(0L, clock.tick());
        logListener.assertWarn("Clock overflow detected");
    }
}