/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.trace;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import net.ranides.assira.junit.NewAssert;
import net.ranides.assira.text.Wildcard;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
@SuppressWarnings({
	"PMD",
    "NestedSynchronizedStatement"
})
public class ThreadUtilsTest {
	
	List<String> DUMP = Arrays.asList(
		"THREAD: main 0x00000001 (monitors=3, locks=1)",
		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock3 * @ net.ranides.assira.trace.ThreadUtilsTest.itestDump(ThreadUtilsTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock2 * @ net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock1 * @ net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
		" - LOCK : java.util.concurrent.locks.ReentrantLock$NonfairSync *",
		"1 ...",
		"THREAD: main 0x00000001 (monitors=3, locks=1)",
		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock3 * @ net.ranides.assira.trace.ThreadUtilsTest.itestDump(ThreadUtilsTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock2 * @ net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadUtilsTest$Lock1 * @ net.ranides.assira.trace.ThreadUtilsTest.testDump(ThreadUtilsTest.java:*)",
		" - LOCK : java.util.concurrent.locks.ReentrantLock$NonfairSync *",
		"2 ...",
		"3 ..."
	);

	@Test
    public void testLocks() {
		ReentrantLock a = new ReentrantLock();
        try {
            a.lock();
            synchronized(new Lock1()) {
                synchronized(new Lock2()) {
                    assertEquals(4,itestLocks());
                }
            }
        } finally {
            a.unlock();
        }
    }
	
	private int itestLocks() {
        synchronized(new Lock3()) {
            return ThreadUtils.get().locks();
        }
    }
	
	@Test
    public void testDump() {
		ReentrantLock a = new ReentrantLock();
        try {
            a.lock();
            synchronized(new Lock1()) {
                synchronized(new Lock2()) {
                    itestDump();
                }
            }
        } finally {
            a.unlock();
        }
		
		
		List<String> out = new ArrayList<>();
		ThreadUtils.dump(true, out::add);
		assertEquals(Arrays.asList(), out);
    }
    
    private void itestDump() {
        synchronized(new Lock3()) {
			List<String> out = new ArrayList<>();
			ThreadUtils.get().dump(out::add);
			out.add("1 ...");
			ThreadUtils.dump(true, out::add);
			out.add("2 ...");
			ThreadUtils.dump(false, out::add);
			out.add("3 ...");
			NewAssert.assertMatch(DUMP, out, (a,b)->Wildcard.match(a,b));
        }
    }
	
	private static class Lock1 { }
    private static class Lock2 { }
    private static class Lock3 { }

}
