/*
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

package jsr166;

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Phaser;
import java.util.concurrent.atomic.LongAccumulator;

import junit.framework.Test;
import junit.framework.TestSuite;

public class LongAccumulatorTest extends JSR166TestCase {
    // android-note: Removed because the CTS runner does a bad job of
    // retrying tests that have suite() declarations.
    //
    // public static void main(String[] args) {
    //     main(suite(), args);
    // }
    // public static Test suite() {
    //     return new TestSuite(LongAccumulatorTest.class);
    // }

    /**
     * default constructed initializes to zero
     */
    public void testConstructor() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        assertEquals(0, ai.get());
    }

    /**
     * accumulate accumulates given value to current, and get returns current value
     */
    public void testAccumulateAndGet() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        ai.accumulate(2);
        assertEquals(2, ai.get());
        ai.accumulate(-4);
        assertEquals(2, ai.get());
        ai.accumulate(4);
        assertEquals(4, ai.get());
    }

    /**
     * reset() causes subsequent get() to return zero
     */
    public void testReset() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        ai.accumulate(2);
        assertEquals(2, ai.get());
        ai.reset();
        assertEquals(0, ai.get());
    }

    /**
     * getThenReset() returns current value; subsequent get() returns zero
     */
    public void testGetThenReset() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        ai.accumulate(2);
        assertEquals(2, ai.get());
        assertEquals(2, ai.getThenReset());
        assertEquals(0, ai.get());
    }

    /**
     * toString returns current value.
     */
    public void testToString() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        assertEquals("0", ai.toString());
        ai.accumulate(1);
        assertEquals(Long.toString(1), ai.toString());
    }

    /**
     * intValue returns current value.
     */
    public void testIntValue() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        assertEquals(0, ai.intValue());
        ai.accumulate(1);
        assertEquals(1, ai.intValue());
    }

    /**
     * longValue returns current value.
     */
    public void testLongValue() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        assertEquals(0, ai.longValue());
        ai.accumulate(1);
        assertEquals(1, ai.longValue());
    }

    /**
     * floatValue returns current value.
     */
    public void testFloatValue() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        assertEquals(0.0f, ai.floatValue());
        ai.accumulate(1);
        assertEquals(1.0f, ai.floatValue());
    }

    /**
     * doubleValue returns current value.
     */
    public void testDoubleValue() {
        LongAccumulator ai = new LongAccumulator(Long::max, 0L);
        assertEquals(0.0, ai.doubleValue());
        ai.accumulate(1);
        assertEquals(1.0, ai.doubleValue());
    }

    /**
     * accumulates by multiple threads produce correct result
     */
    public void testAccumulateAndGetMT() {
        final int incs = 1000000;
        final int nthreads = 4;
        final ExecutorService pool = Executors.newCachedThreadPool();
        LongAccumulator a = new LongAccumulator(Long::max, 0L);
        Phaser phaser = new Phaser(nthreads + 1);
        for (int i = 0; i < nthreads; ++i)
            pool.execute(new AccTask(a, phaser, incs));
        phaser.arriveAndAwaitAdvance();
        phaser.arriveAndAwaitAdvance();
        long expected = incs - 1;
        long result = a.get();
        assertEquals(expected, result);
        pool.shutdown();
    }

    static final class AccTask implements Runnable {
        final LongAccumulator acc;
        final Phaser phaser;
        final int incs;
        volatile long result;
        AccTask(LongAccumulator acc, Phaser phaser, int incs) {
            this.acc = acc;
            this.phaser = phaser;
            this.incs = incs;
        }

        public void run() {
            phaser.arriveAndAwaitAdvance();
            LongAccumulator a = acc;
            for (int i = 0; i < incs; ++i)
                a.accumulate(i);
            result = a.get();
            phaser.arrive();
        }
    }

}
