/*
 * Copyright (c) 2007 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package org.mockitousage.configuration;


import org.assertj.core.api.Condition;
import org.junit.Test;
import org.mockito.internal.configuration.ConfigurationAccess;
import org.mockitoutil.SimplePerRealmReloadingClassLoader;

import java.util.concurrent.Callable;

import static org.mockito.Mockito.mock;

@SuppressWarnings("unchecked")
public class ClassCacheVersusClassReloadingTest {
    // TODO refactor to use ClassLoaders

    private SimplePerRealmReloadingClassLoader testMethodClassLoaderRealm = new SimplePerRealmReloadingClassLoader(reloadMockito());

    @Test
    public void should_not_throw_ClassCastException_when_objenesis_cache_disabled() throws Exception {
        prepareMockitoAndDisableObjenesisCache();

        doInNewChildRealm(testMethodClassLoaderRealm, "org.mockitousage.configuration.ClassCacheVersusClassReloadingTest$DoTheMocking");
        doInNewChildRealm(testMethodClassLoaderRealm, "org.mockitousage.configuration.ClassCacheVersusClassReloadingTest$DoTheMocking");
    }

    private Condition<Throwable> cceIsThrownFrom(final String stacktraceElementDescription) {
        return new Condition<Throwable>() {
            @Override
            public boolean matches(Throwable throwable) {
                StackTraceElement[] stackTrace = throwable.getStackTrace();
                for (StackTraceElement stackTraceElement : stackTrace) {
                    if (stackTraceElement.toString().contains(stacktraceElementDescription)) {
                        return true;
                    }
                }

                return false;
            }
        };
    }

    public static class DoTheMocking implements Callable {
        public Object call() throws Exception {
            Class clazz = this.getClass().getClassLoader().loadClass("org.mockitousage.configuration.ClassToBeMocked");
            return mock(clazz);
        }
    }


    private static void doInNewChildRealm(ClassLoader parentRealm, String callableCalledInClassLoaderRealm) throws Exception {
        new SimplePerRealmReloadingClassLoader(parentRealm, reloadScope()).doInRealm(callableCalledInClassLoaderRealm);
    }

    private static SimplePerRealmReloadingClassLoader.ReloadClassPredicate reloadScope() {
        return new SimplePerRealmReloadingClassLoader.ReloadClassPredicate() {
            public boolean acceptReloadOf(String qualifiedName) {
                return "org.mockitousage.configuration.ClassCacheVersusClassReloadingTest$DoTheMocking".equals(qualifiedName)
                    || "org.mockitousage.configuration.ClassToBeMocked".equals(qualifiedName);
            }
        };
    }

    private void prepareMockitoAndDisableObjenesisCache() throws Exception {
        testMethodClassLoaderRealm.doInRealm("org.mockitousage.configuration.ClassCacheVersusClassReloadingTest$PrepareMockito");
    }

    public static class PrepareMockito implements Callable {
        public Object call() throws Exception {
            Class.forName("org.mockito.Mockito");
            ConfigurationAccess.getConfig().overrideEnableClassCache(false);
            return Boolean.TRUE;
        }
    }

    private static SimplePerRealmReloadingClassLoader.ReloadClassPredicate reloadMockito() {
        return new SimplePerRealmReloadingClassLoader.ReloadClassPredicate() {
            public boolean acceptReloadOf(String qualifiedName) {
                return (!qualifiedName.contains("net.bytebuddy") && qualifiedName.contains("org.mockito"));
            }
        };
    }

}

@@ -159,47 +159,8 @@
 ;%0A%0A%0A
-import org.assertj.core.api.Condition;%0A
 impo
@@ -1087,610 +1087,8 @@
  %7D%0A%0A
-    private Condition%3CThrowable%3E cceIsThrownFrom(final String stacktraceElementDescription) %7B%0A        return new Condition%3CThrowable%3E() %7B%0A            @Override%0A            public boolean matches(Throwable throwable) %7B%0A                StackTraceElement%5B%5D stackTrace = throwable.getStackTrace();%0A                for (StackTraceElement stackTraceElement : stackTrace) %7B%0A                    if (stackTraceElement.toString().contains(stacktraceElementDescription)) %7B%0A                        return true;%0A                    %7D%0A                %7D%0A%0A                return false;%0A            %7D%0A        %7D;%0A    %7D%0A%0A
     
@@ -1131,32 +1131,40 @@
 lements Callable
+%3CObject%3E
  %7B%0A        publi
@@ -1364,16 +1364,15 @@
   %7D%0A
+
     %7D%0A%0A
-%0A
     

remove dead code in ClassCacheVersusClassReloadingTest