package io.quarkus.cache.test.runtime;

import static org.junit.jupiter.api.Assertions.assertTrue;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.cache.CacheInvalidate;
import io.quarkus.cache.CacheInvalidateAll;
import io.quarkus.cache.CacheResult;
import io.quarkus.test.QuarkusUnitTest;

public class NoOpCacheTest {

    private static final String CACHE_NAME = "test-cache";
    private static final Object KEY = new Object();

    @RegisterExtension
    static final QuarkusUnitTest TEST = new QuarkusUnitTest().setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
            .addAsResource(new StringAsset("quarkus.cache.enabled=false"), "application.properties")
            .addClass(CachedService.class));

    @Inject
    CachedService cachedService;

    @Test
    public void testAllCacheAnnotations() {
        // STEP 1
        // Action: @CacheResult-annotated method call.
        // Expected effect: method invoked and result not cached.
        // Verified by: STEP 2.
        String value1 = cachedService.cachedMethod(KEY);

        // STEP 2
        // Action: same call as STEP 1.
        // Expected effect: method invoked and result not cached.
        // Verified by: different objects references between STEPS 1 and 2 results.
        String value2 = cachedService.cachedMethod(KEY);
        assertTrue(value1 != value2);

        // The following methods have no effect at all, but let's check if they're running fine anyway.
        cachedService.invalidate(KEY);
        cachedService.invalidateAll();
    }

    @Singleton
    static class CachedService {

        @CacheResult(cacheName = CACHE_NAME)
        public String cachedMethod(Object key) {
            return new String();
        }

        @CacheInvalidate(cacheName = CACHE_NAME)
        public void invalidate(Object key) {
        }

        @CacheInvalidateAll(cacheName = CACHE_NAME)
        public void invalidateAll() {
        }
    }
}

@@ -86,20 +86,171 @@
 s.assert
-True
+Equals;%0Aimport static org.junit.jupiter.api.Assertions.assertThrows;%0Aimport static org.junit.jupiter.api.Assertions.assertTrue;%0A%0Aimport java.io.IOException
 ;%0A%0Aimpor
@@ -846,16 +846,95 @@
 bject();
+%0A    private static final String FORCED_EXCEPTION_MESSAGE = %22Forced exception%22;
 %0A%0A    @R
@@ -2052,384 +2052,1903 @@
    @
-Singleton%0A    static class CachedService %7B%0A%0A        @CacheResult(cacheName = CACHE_NAME)%0A        public String cachedMethod(Object key) %7B%0A            return new String();%0A        %7D%0A%0A        @CacheInvalidate(cacheName = CACHE_NAME)%0A        public void invalidate(Object key) %7B%0A        %7D%0A%0A        @CacheInvalidateAll(cacheName = CACHE_NAME)%0A        public void invalidateAll() %7B
+Test%0A    public void testRuntimeExceptionThrowDuringCacheComputation() %7B%0A        NumberFormatException e = assertThrows(NumberFormatException.class, () -%3E %7B%0A            cachedService.throwRuntimeExceptionDuringCacheComputation();%0A        %7D);%0A        assertEquals(FORCED_EXCEPTION_MESSAGE, e.getMessage());%0A    %7D%0A%0A    @Test%0A    public void testCheckedExceptionThrowDuringCacheComputation() %7B%0A        IOException e = assertThrows(IOException.class, () -%3E %7B%0A            cachedService.throwCheckedExceptionDuringCacheComputation();%0A        %7D);%0A        assertEquals(FORCED_EXCEPTION_MESSAGE, e.getMessage());%0A    %7D%0A%0A    @Test%0A    public void testErrorThrowDuringCacheComputation() %7B%0A        OutOfMemoryError e = assertThrows(OutOfMemoryError.class, () -%3E %7B%0A            cachedService.throwErrorDuringCacheComputation();%0A        %7D);%0A        assertEquals(FORCED_EXCEPTION_MESSAGE, e.getMessage());%0A    %7D%0A%0A    @Singleton%0A    static class CachedService %7B%0A%0A        @CacheResult(cacheName = CACHE_NAME)%0A        public String cachedMethod(Object key) %7B%0A            return new String();%0A        %7D%0A%0A        @CacheInvalidate(cacheName = CACHE_NAME)%0A        public void invalidate(Object key) %7B%0A        %7D%0A%0A        @CacheInvalidateAll(cacheName = CACHE_NAME)%0A        public void invalidateAll() %7B%0A        %7D%0A%0A        @CacheResult(cacheName = %22runtime-exception-cache%22)%0A        public String throwRuntimeExceptionDuringCacheComputation() %7B%0A            throw new NumberFormatException(FORCED_EXCEPTION_MESSAGE);%0A        %7D%0A%0A        @CacheResult(cacheName = %22checked-exception-cache%22)%0A        public String throwCheckedExceptionDuringCacheComputation() throws IOException %7B%0A            throw new IOException(FORCED_EXCEPTION_MESSAGE);%0A        %7D%0A%0A        @CacheResult(cacheName = %22error-cache%22)%0A        public String throwErrorDuringCacheComputation() %7B%0A            throw new OutOfMemoryError(FORCED_EXCEPTION_MESSAGE);
 %0A   

Test exceptions thrown during NoOpCache computations