package net.kencochrane.raven.connection;

import mockit.*;
import net.kencochrane.raven.Raven;
import net.kencochrane.raven.event.Event;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

public class AsyncConnectionTest {
    @Tested
    private AsyncConnection asyncConnection;
    @Injectable
    private Connection mockConnection;
    @Injectable
    private ExecutorService mockExecutorService;
    @Mocked("addShutdownHook")
    private Runtime mockRuntime;

    @BeforeMethod
    public void setUp() throws Exception {
        // Reset Tested
        asyncConnection = null;
        new NonStrictExpectations() {{
            mockExecutorService.awaitTermination(anyLong, (TimeUnit) any);
            result = true;
        }};
    }

    @AfterMethod
    public void tearDown() throws Exception {
        // Reset the expectation that has been already removed.
        new NonStrictExpectations() {{
            mockExecutorService.awaitTermination(anyLong, (TimeUnit) any);
            result = true;
        }};
        // Ensure that the shutdown hooks are removed
        asyncConnection.close();
    }

    @Test
    public void verifyShutdownHookIsAdded() throws Exception {
        new AsyncConnection(mockConnection, mockExecutorService);

        new Verifications() {{
            mockRuntime.addShutdownHook((Thread) any);
        }};
    }

    @Test
    public void verifyShutdownHookSetManagedByRavenAndCloseConnection(
            @Mocked({"startManagingThread", "stopManagingThread"}) Raven mockRaven) throws Exception {
        new NonStrictExpectations() {{
            mockRuntime.addShutdownHook((Thread) any);
            result = new Delegate<Void>() {
                public void addShutdownHook(Thread thread) {
                    thread.run();
                }
            };
        }};

        new AsyncConnection(mockConnection, mockExecutorService);

        new VerificationsInOrder() {{
            Raven.startManagingThread();
            mockConnection.close();
            Raven.stopManagingThread();
        }};
    }

    @Test
    public void ensureFailingShutdownHookStopsBeingManaged(
            @Mocked({"startManagingThread", "stopManagingThread"}) Raven mockRaven) throws Exception {
        new NonStrictExpectations() {{
            mockRuntime.addShutdownHook((Thread) any);
            result = new Delegate<Void>() {
                public void addShutdownHook(Thread thread) {
                    thread.run();
                }
            };
            mockConnection.close();
            result = new RuntimeException("Close operation failed");
        }};

        new AsyncConnection(mockConnection, mockExecutorService);

        new Verifications() {{
            Raven.stopManagingThread();
        }};
    }

    @Test
    public void testCloseOperation() throws Exception {
        asyncConnection.close();

        new Verifications() {{
            mockConnection.close();
            mockExecutorService.awaitTermination(anyLong, (TimeUnit) any);
        }};
    }

    @Test
    public void testSendEventQueued(@Injectable final Event mockEvent) throws Exception {
        asyncConnection.send(mockEvent);

        new Verifications() {{
            mockExecutorService.execute((Runnable) any);
        }};
    }

    @Test
    public void testQueuedEventExecuted(@Injectable final Event mockEvent) throws Exception {
        new Expectations() {{
            mockExecutorService.execute((Runnable) any);
            result = new Delegate() {
                public void execute(Runnable runnable) {
                    runnable.run();
                }
            };
        }};

        asyncConnection.send(mockEvent);

        new Verifications() {{
            mockConnection.send(mockEvent);
        }};
    }
}

@@ -681,64 +681,8 @@
 n %7B%0A
-        // Reset Tested%0A        asyncConnection = null;%0A
     
@@ -842,27 +842,20 @@
 %7D%0A%0A    @
-AfterMethod
+Test
 %0A    pub
@@ -867,16 +867,33 @@
 oid 
-tearDown
+verifyShutdownHookIsAdded
 () t
@@ -925,380 +925,116 @@
  // 
-Reset the expectation that has been already removed.%0A        new NonStrictExpectations() %7B%7B%0A            mockExecutorService.awaitTermination(anyLong, (TimeUnit) any);%0A            result = true;%0A        %7D%7D;%0A        // Ensure that the shutdown hooks are removed%0A        asyncConnection.close();%0A    %7D%0A%0A    @Test%0A    public void verifyShutdownHookIsAdded() throws Exception %7B
+Ensure that the shutdown hooks for the unused @Tested instance are removed%0A        asyncConnection.close();%0A
 %0A   
@@ -1378,32 +1378,152 @@
 ows Exception %7B%0A
+        // Ensure that the shutdown hooks for the unused @Tested instance are removed%0A        asyncConnection.close();%0A%0A
         new NonS
@@ -2191,32 +2191,152 @@
 ows Exception %7B%0A
+        // Ensure that the shutdown hooks for the unused @Tested instance are removed%0A        asyncConnection.close();%0A%0A
         new NonS
@@ -3354,32 +3354,150 @@
 ny);%0A        %7D%7D;
+%0A%0A        // Ensure that the shutdown hooks for the used @Tested instance are removed%0A        asyncConnection.close();
 %0A    %7D%0A%0A    @Tes
@@ -3604,16 +3604,25 @@
     new 
+NonStrict
 Expectat
@@ -3989,21 +3989,139 @@
 %0A        %7D%7D;
+%0A%0A        // Ensure that the shutdown hooks for the used @Tested instance are removed%0A        asyncConnection.close();
 %0A    %7D%0A%7D%0A

Fix test to comply with the changes in JMockit issue 348