/*
 * @author Ranides Atterwim {@literal <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 {@literal <ranides@gmail.com>}
 */
@SuppressWarnings({
	"PMD",
    "NestedSynchronizedStatement"
})
public class ThreadDumpTest {
	
	List<String> DUMP = Arrays.asList(
		"THREAD: main 0x00000001 (monitors=3, locks=1)",
		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock3 * @ *net.ranides.assira.trace.ThreadDumpTest.itestDump(ThreadDumpTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock2 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock1 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
		" - LOCK : java.util.concurrent.locks.ReentrantLock$NonfairSync *",
		"1 ...",
		"THREAD: main 0x00000001 (monitors=3, locks=1)",
		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock3 * @ *net.ranides.assira.trace.ThreadDumpTest.itestDump(ThreadDumpTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock2 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.java:*)",
		" - MONITOR : net.ranides.assira.trace.ThreadDumpTest$Lock1 * @ *net.ranides.assira.trace.ThreadDumpTest.testDump(ThreadDumpTest.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 new ThreadDump().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<>();
		ThreadDump.printIf(true, out::add);
		assertEquals(Arrays.asList(), out);
    }
    
    private void itestDump() {
        synchronized(new Lock3()) {
			List<String> out = new ArrayList<>();
			new ThreadDump().print(out::add);
			out.add("1 ...");
            ThreadDump.printIf(true, out::add);
			out.add("2 ...");
            ThreadDump.printIf(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 { }

}
