/*
 * Copyright 2016-2020 chronicle.software
 *
 * https://chronicle.software
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.openhft.chronicle.core.time;

import net.openhft.chronicle.core.FlakyTestRunner;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.OS;
import net.openhft.chronicle.core.util.Histogram;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;

import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class SystemTimeProviderTest {
    @Test
    public void currentTimeMicros() throws IllegalStateException {
        FlakyTestRunner.run(Jvm.isArm() || OS.isWindows() || OS.isMacOSX(), this::doCurrentTimeMicros);
    }

    static void assertBetween(long min, long actual, long max) {
        if (min <= actual && actual <= max)
            return;
        throw new AssertionError("Not in range " + min + " <= " + actual + " <= " + max);
    }

    private void doCurrentTimeMicros() throws IllegalStateException {
        @NotNull TimeProvider tp = SystemTimeProvider.INSTANCE;
        long minDiff = 0;
        long maxDiff = 0;
        long lastTimeMicros;
        long start;

        int error = OS.isWindows() || Jvm.isArm() ? 12 : 1;
        for (int i = 0; i <= 20; i++) {
            minDiff = 10;
            maxDiff = 995;
            lastTimeMicros = 0;
            start = System.currentTimeMillis();

            do {
                long now0 = tp.currentTimeMillis();
                long time2 = tp.currentTimeMicros();
                long now1 = tp.currentTimeMillis();
                if (now1 - now0 > 1) {
                    System.out.println("jump: " + (now1 - now0));
                    continue;
                }

                long now = now1 * 1000;
                long diff = time2 - now;
                if (minDiff > diff) {
                    minDiff = diff;
//                    System.out.println("min: " + minDiff);
                }
                if (maxDiff < diff) {
                    maxDiff = diff;
//                    System.out.println("max: " + maxDiff);
                }
                long ns = System.nanoTime();
                while (System.nanoTime() < ns + 100)
                    Jvm.nanoPause();
                assertTrue(time2 >= lastTimeMicros);
                lastTimeMicros = time2;
            } while (System.currentTimeMillis() < start + 500);

            try {
                assertBetween(-5 * error, minDiff, 5 * error);
                assertBetween(990, maxDiff, 1000 + 30 * error);
                break;
            } catch (AssertionError e) {
                continue;
            }
        }
        assertBetween(-5 * error, minDiff, 5 * error);
        assertBetween(990, maxDiff, 1000 + 30 * error);
    }

    @Test
    public void currentTime() throws IllegalStateException {
        for (int i = 3; i >= 0; i--) {
            TimeProvider tp = SystemTimeProvider.INSTANCE;
            long time1 = tp.currentTime(TimeUnit.SECONDS);
            long time2 = tp.currentTimeMillis();
            long time3 = tp.currentTimeMicros();
            long time4 = tp.currentTimeNanos();
            try {
                assertEquals(time1, time2 / 1000 + 1, 1);
                assertEquals(time2, time3 / 1000 + 10, 10);
                assertEquals(time3, time4 / 1000 + 5000, 10000);
            } catch (AssertionError ae) {
                if (i == 0)
                    throw ae;
            }
        }
    }

    @Test
    public void resolution() {
        for (int j = 0; j < 3; j++) {
            Histogram h = new Histogram(32, 10, 1);
            long last = SystemTimeProvider.INSTANCE.currentTimeNanos();
            for (int i = 0; i < 5000000; i++) {
                long next = SystemTimeProvider.INSTANCE.currentTimeNanos();
                h.sampleNanos(next - last);
                Jvm.nanoPause();

                last = next;
            }
            System.out.println(h.toMicrosFormat());
        }
    }
}
@@ -963,53 +963,8 @@
 t;%0A%0A
-import static org.junit.Assert.assertEquals;%0A
 impo
@@ -3720,31 +3720,46 @@
       assert
-Equals(
+Between(time2 / 1000, 
 time1, time2
@@ -3772,12 +3772,9 @@
 0 + 
-1, 1
+2
 );%0A 
@@ -3790,31 +3790,50 @@
       assert
-Equals(
+Between(time3 / 1000 - 1, 
 time2, time3
@@ -3842,21 +3842,17 @@
  1000 + 
-10, 1
+2
 0);%0A    
@@ -3873,15 +3873,36 @@
 sert
-Equals(
+Between(time4 / 1000 - 100, 
 time
@@ -3923,16 +3923,10 @@
 0 + 
-5000, 10
+2_
 000)
@@ -3965,24 +3965,56 @@
 Error ae) %7B%0A
+                Thread.yield();%0A
             
@@ -4083,23 +4083,24 @@
       %7D%0A
-
     %7D%0A%0A
+%0A
     @Tes

Improve test stability on Java 11