/*
 * Copyright (c) 2017 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package org.mockito.internal.framework;

import org.junit.After;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.MockSettings;
import org.mockito.StateMaster;
import org.mockito.exceptions.misusing.RedundantListenerException;
import org.mockito.internal.configuration.plugins.Plugins;
import org.mockito.listeners.MockCreationListener;
import org.mockito.listeners.MockitoListener;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.InlineMockMaker;
import org.mockitoutil.TestBase;

import java.util.List;
import java.util.Set;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.withSettings;
import static org.mockitoutil.ThrowableAssert.assertThat;

public class DefaultMockitoFrameworkTest extends TestBase {

    private DefaultMockitoFramework framework = new DefaultMockitoFramework();

    @After public void clearListeners() {
        new StateMaster().clearMockitoListeners();
    }

    @Test(expected = IllegalArgumentException.class)
    public void prevents_adding_null_listener() {
        framework.addListener(null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void prevents_removing_null_listener() {
        framework.removeListener(null);
    }

    @Test
    public void ok_to_remove_unknown_listener() {
        //it is safe to remove listener that was not added before
        framework.removeListener(new MockitoListener() {});
    }

    @Test
    public void ok_to_remove_listener_multiple_times() {
        MockitoListener listener = new MockitoListener() {};

        //when
        framework.addListener(listener);

        //then it is ok to:
        framework.removeListener(listener);
        framework.removeListener(listener);
    }

    @Test
    public void adds_creation_listener() {
        //given creation listener is added
        MockCreationListener listener = mock(MockCreationListener.class);
        framework.addListener(listener);

        //when
        MockSettings settings = withSettings().name("my list");
        List mock = mock(List.class, settings);
        Set mock2 = mock(Set.class);

        //then
        verify(listener).onMockCreated(eq(mock), any(MockCreationSettings.class));
        verify(listener).onMockCreated(eq(mock2), any(MockCreationSettings.class));
        verifyNoMoreInteractions(listener);
    }

    @SuppressWarnings({"CheckReturnValue", "MockitoUsage"})
    @Test
    public void removes_creation_listener() {
        //given creation listener is added
        MockCreationListener listener = mock(MockCreationListener.class);
        framework.addListener(listener);

        //and hooked up correctly
        mock(List.class);
        verify(listener).onMockCreated(ArgumentMatchers.any(), any(MockCreationSettings.class));

        //when
        framework.removeListener(listener);
        mock(Set.class);

        //then
        verifyNoMoreInteractions(listener);
    }

    @Test public void prevents_duplicate_listeners_of_the_same_type() {
        //given creation listener is added
        framework.addListener(new MyListener());

        assertThat(new Runnable() {
            @Override
            public void run() {
                framework.addListener(new MyListener());
            }
        })  .throwsException(RedundantListenerException.class)
            .throwsMessage("\n" +
                    "Problems adding Mockito listener.\n" +
                    "Listener of type 'MyListener' has already been added and not removed.\n" +
                    "It indicates that previous listener was not removed according to the API.\n" +
                    "When you add a listener, don't forget to remove the listener afterwards:\n" +
                    "  Mockito.framework().removeListener(myListener);\n" +
                    "For more information, see the javadoc for RedundantListenerException class.");
    }

    @Test
    public void clears_all_mocks() {
        List list1 = mock(List.class);
        assertTrue(mockingDetails(list1).isMock());
        List list2 = mock(List.class);
        assertTrue(mockingDetails(list2).isMock());

        framework.clearInlineMocks();

        if (Plugins.getMockMaker() instanceof InlineMockMaker) {
            assertFalse(mockingDetails(list1).isMock());
            assertFalse(mockingDetails(list2).isMock());
        }
    }

    @Test
    public void clears_mock() {
        List list1 = mock(List.class);
        assertTrue(mockingDetails(list1).isMock());
        List list2 = mock(List.class);
        assertTrue(mockingDetails(list2).isMock());

        framework.clearInlineMock(list1);

        if (Plugins.getMockMaker() instanceof InlineMockMaker) {
            assertFalse(mockingDetails(list1).isMock());
            assertTrue(mockingDetails(list2).isMock());
        }
    }

    private static class MyListener implements MockitoListener {}
}

@@ -783,16 +783,59 @@
 rtTrue;%0A
+import static org.junit.Assume.assumeTrue;%0A
 import s
@@ -4442,24 +4442,168 @@
 l_mocks() %7B%0A
+        //clearing mocks only works with inline mocking%0A        assumeTrue(Plugins.getMockMaker() instanceof InlineMockMaker);%0A%0A        //given%0A
         List
@@ -4765,32 +4765,47 @@
 t2).isMock());%0A%0A
+        //when%0A
         framewor
@@ -4839,69 +4839,15 @@
     
-if (Plugins.getMockMaker() instanceof InlineMockMaker) %7B%0A    
+//then%0A
     
@@ -4895,36 +4895,32 @@
 ock());%0A        
-  
-  
 assertFalse(mock
@@ -4944,34 +4944,24 @@
 .isMock());%0A
-        %7D%0A
     %7D%0A%0A    @
@@ -4993,24 +4993,168 @@
 rs_mock() %7B%0A
+        //clearing mocks only works with inline mocking%0A        assumeTrue(Plugins.getMockMaker() instanceof InlineMockMaker);%0A%0A        //given%0A
         List
@@ -5316,32 +5316,47 @@
 t2).isMock());%0A%0A
+        //when%0A
         framewor
@@ -5394,64 +5394,14 @@
     
-if (Plugins.getMockMaker() instanceof InlineMockMaker) %7B
+//then
 %0A   
@@ -5401,28 +5401,24 @@
 hen%0A        
-    
 assertFalse(
@@ -5454,28 +5454,24 @@
 ));%0A        
-    
 assertTrue(m
@@ -5502,26 +5502,16 @@
 ock());%0A
-        %7D%0A
     %7D%0A%0A 

Replace conditional with JUnit assume