From 99bf56b15191cd4a645138fea904e854ee5b743a Mon Sep 17 00:00:00 2001 From: Ben Manes Date: Sat, 1 May 2021 22:34:56 -0700 Subject: [PATCH] additional test coverage --- .../caffeine/cache/AsyncLoadingCacheTest.java | 16 ++++ .../caffeine/cache/CaffeineSpecTest.java | 15 ++++ .../caffeine/cache/LinkedDequeTest.java | 8 ++ .../caffeine/cache/RefreshAfterWriteTest.java | 16 +++- .../caffeine/cache/SchedulerTest.java | 21 ++++- .../caffeine/cache/TimerWheelTest.java | 23 +++++- .../cache/stats/StatsCounterTest.java | 7 ++ gradle/dependencies.gradle | 2 +- .../caffeine/jcache/copy/AbstractCopier.java | 21 ++--- .../copy/JavaSerializationCopierTest.java | 80 ++++++++++++------- 10 files changed, 160 insertions(+), 49 deletions(-) diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncLoadingCacheTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncLoadingCacheTest.java index 797be65772..115152e9d9 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncLoadingCacheTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/AsyncLoadingCacheTest.java @@ -405,6 +405,22 @@ public void bulk_function_null() { AsyncCacheLoader.bulk(f); } + @Test + public void bulk_function_absent() throws Exception { + AsyncCacheLoader loader = AsyncCacheLoader.bulk(keys -> Map.of()); + assertThat(loader.asyncLoadAll(Set.of(), Runnable::run).join(), is(Map.of())); + assertThat(loader.asyncLoad(1, Runnable::run).join(), is(nullValue())); + } + + @Test + public void bulk_function_present() throws Exception { + AsyncCacheLoader loader = AsyncCacheLoader.bulk(keys -> { + return keys.stream().collect(toMap(identity(), identity())); + }); + assertThat(loader.asyncLoadAll(Set.of(1, 2), Runnable::run).join(), is(Map.of(1, 1, 2, 2))); + assertThat(loader.asyncLoad(1, Runnable::run).join(), is(1)); + } + @SuppressWarnings("CheckReturnValue") @Test(expectedExceptions = NullPointerException.class) public void bulk_bifunction_null() { diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/CaffeineSpecTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/CaffeineSpecTest.java index 4f30a9b7f7..d973613e02 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/CaffeineSpecTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/CaffeineSpecTest.java @@ -57,6 +57,21 @@ public final class CaffeineSpecTest { static final long UNSET_LONG = UNSET_INT; + @Test(expectedExceptions = IllegalArgumentException.class) + public void parseInt_exception() { + CaffeineSpec.parseInt("key", "value"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void parseLong_exception() { + CaffeineSpec.parseLong("key", "value"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void parseTimeUnit_exception() { + CaffeineSpec.parseTimeUnit("key", "value"); + } + @Test(dataProvider = "caches") @CacheSpec(initialCapacity = {InitialCapacity.DEFAULT, InitialCapacity.FULL}, population = Population.EMPTY, compute = Compute.SYNC, diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LinkedDequeTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LinkedDequeTest.java index 0d03fc75a8..7e19eb76f6 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LinkedDequeTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/LinkedDequeTest.java @@ -738,6 +738,14 @@ public void iterator_removal(LinkedDeque deque) { assertThat(deque, hasSize(SIZE - 1)); } + @Test(dataProvider = "full", expectedExceptions = IllegalStateException.class) + public void iterator_removal_exception(LinkedDeque deque) { + PeekingIterator iterator = deque.iterator(); + iterator.next(); + iterator.remove(); + iterator.remove(); + } + @Test(dataProvider = "empty", expectedExceptions = NoSuchElementException.class) public void descendingIterator_noMoreElements(LinkedDeque deque) { deque.descendingIterator().next(); diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java index cfc0253532..e5f56d5a22 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/RefreshAfterWriteTest.java @@ -29,6 +29,7 @@ import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; +import java.time.Duration; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -397,16 +398,27 @@ public void refreshes(LoadingCache cache, CacheContext context @Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, refreshAfterWrite = Expire.ONE_MINUTE) - public void getExpiresAfter(CacheContext context, + public void getRefreshesAfter(CacheContext context, @RefreshAfterWrite FixedRefresh refreshAfterWrite) { + assertThat(refreshAfterWrite.getRefreshesAfter().toMinutes(), is(1L)); assertThat(refreshAfterWrite.getRefreshesAfter(TimeUnit.MINUTES), is(1L)); } @Test(dataProvider = "caches") @CacheSpec(implementation = Implementation.Caffeine, refreshAfterWrite = Expire.ONE_MINUTE) - public void setExpiresAfter(CacheContext context, + public void setRefreshesAfter(CacheContext context, @RefreshAfterWrite FixedRefresh refreshAfterWrite) { refreshAfterWrite.setRefreshesAfter(2, TimeUnit.MINUTES); + assertThat(refreshAfterWrite.getRefreshesAfter().toMinutes(), is(2L)); + assertThat(refreshAfterWrite.getRefreshesAfter(TimeUnit.MINUTES), is(2L)); + } + + @Test(dataProvider = "caches") + @CacheSpec(implementation = Implementation.Caffeine, refreshAfterWrite = Expire.ONE_MINUTE) + public void setRefreshesAfter_duration(CacheContext context, + @RefreshAfterWrite FixedRefresh refreshAfterWrite) { + refreshAfterWrite.setRefreshesAfter(Duration.ofMinutes(2)); + assertThat(refreshAfterWrite.getRefreshesAfter().toMinutes(), is(2L)); assertThat(refreshAfterWrite.getRefreshesAfter(TimeUnit.MINUTES), is(2L)); } diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/SchedulerTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/SchedulerTest.java index c1db62bf1b..0bfc99ed29 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/SchedulerTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/SchedulerTest.java @@ -21,6 +21,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.nullValue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -44,6 +45,7 @@ import com.github.benmanes.caffeine.testing.ConcurrentTestHarness; import com.google.common.collect.ImmutableSet; import com.google.common.testing.NullPointerTester; +import com.google.common.util.concurrent.Futures; /** * @author ben.manes@gmail.com (Ben Manes) @@ -90,6 +92,16 @@ public void disabledScheduler() { assertThat(future, is(DisabledFuture.INSTANCE)); } + @Test + public void disabledFuture() throws Exception { + assertThat(DisabledFuture.INSTANCE.isDone(), is(true)); + assertThat(DisabledFuture.INSTANCE.isCancelled(), is(false)); + assertThat(DisabledFuture.INSTANCE.cancel(false), is(false)); + assertThat(DisabledFuture.INSTANCE.cancel(true), is(false)); + assertThat(DisabledFuture.INSTANCE.get(), is(nullValue())); + assertThat(DisabledFuture.INSTANCE.get(0, TimeUnit.SECONDS), is(nullValue())); + } + @Test public void disabledFuture_null() { npeTester.testAllPublicInstanceMethods(DisabledFuture.INSTANCE); @@ -117,7 +129,14 @@ public void guardedScheduler_nullFuture() { @Test public void guardedScheduler() { - Future future = Scheduler.guardedScheduler(Scheduler.disabledScheduler()) + Future future = Scheduler.guardedScheduler((r, e, d, u) -> Futures.immediateVoidFuture()) + .schedule(Runnable::run, () -> {}, 1, TimeUnit.MINUTES); + assertThat(future, is(Futures.immediateVoidFuture())); + } + + @Test + public void guardedScheduler_exception() { + Future future = Scheduler.guardedScheduler((r, e, d, u) -> { throw new RuntimeException(); }) .schedule(Runnable::run, () -> {}, 1, TimeUnit.MINUTES); assertThat(future, is(DisabledFuture.INSTANCE)); } diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java index 67139fc681..83fb372de4 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/TimerWheelTest.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.sameInstance; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.times; @@ -48,6 +49,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -135,6 +137,23 @@ public void advance(long clock) { verify(cache).evictEntry(any(), any(), anyLong()); } + @Test + public void advance_exception() { + Mockito.doThrow(new IllegalStateException()) + .when(cache).evictEntry(captor.capture(), any(), anyLong()); + var timer = new Timer(timerWheel.nanos + SPANS[1]); + + timerWheel.nanos = 0L; + timerWheel.schedule(timer); + try { + timerWheel.advance(Long.MAX_VALUE); + Assert.fail(); + } catch (IllegalStateException e) { + assertThat(timerWheel.nanos, is(0L)); + assertThat(timerWheel.wheel[1][1].getNextInVariableOrder(), is(sameInstance(timer))); + } + } + @Test(dataProvider = "clock") public void getExpirationDelay_empty(long clock) { when(cache.evictEntry(any(), any(), anyLong())).thenReturn(true); @@ -232,7 +251,7 @@ public Iterator providesClock() { @DataProvider(name = "schedule") public Iterator providesSchedule() { var args = new ArrayList(); - for (var clock : CLOCKS) { + for (long clock : CLOCKS) { args.add(new Object[] { clock, TimeUnit.SECONDS.toNanos(10), 0 }); args.add(new Object[] { clock, TimeUnit.MINUTES.toNanos(3), 2 }); args.add(new Object[] { clock, TimeUnit.MINUTES.toNanos(10), 3 }); @@ -268,7 +287,7 @@ private void checkTimerWheel(long duration) { private LongArrayList getTimers(Node sentinel) { LongArrayList timers = new LongArrayList(); for (Node node = sentinel.getNextInVariableOrder(); - node != sentinel; node = node.getNextInVariableOrder()) { + node != sentinel; node = node.getNextInVariableOrder()) { timers.add(node.getVariableTime()); } return timers; diff --git a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/stats/StatsCounterTest.java b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/stats/StatsCounterTest.java index 7a975ed74a..f2c60e83c4 100644 --- a/caffeine/src/test/java/com/github/benmanes/caffeine/cache/stats/StatsCounterTest.java +++ b/caffeine/src/test/java/com/github/benmanes/caffeine/cache/stats/StatsCounterTest.java @@ -17,6 +17,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.sameInstance; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -96,6 +97,12 @@ public void guarded() { assertThat(counter.snapshot().toString(), is(expected.toString())); } + @Test + public void guarded_sameInstance() { + StatsCounter counter = StatsCounter.guardedStatsCounter(new ConcurrentStatsCounter()); + assertThat(StatsCounter.guardedStatsCounter(counter), is(sameInstance(counter))); + } + @Test public void guarded_exception() { StatsCounter statsCounter = Mockito.mock(StatsCounter.class); diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle index c063f7734e..cb864c32cc 100644 --- a/gradle/dependencies.gradle +++ b/gradle/dependencies.gradle @@ -179,7 +179,7 @@ ext { "org.osgi:org.osgi.util.promise:${testVersions.osgiUtilPromise}", "org.ops4j.pax.exam:pax-exam-container-native:${testVersions.paxExam}", "org.ops4j.pax.exam:pax-exam-link-mvn:${testVersions.paxExam}", - "org.ops4j.pax.url:pax-url-aether:2.6.5", + "org.ops4j.pax.url:pax-url-aether:2.6.7", ], testng: [ dependencies.create("org.testng:testng:${testVersions.testng}") { diff --git a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/copy/AbstractCopier.java b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/copy/AbstractCopier.java index 435c409dc7..89986d1e0e 100644 --- a/jcache/src/main/java/com/github/benmanes/caffeine/jcache/copy/AbstractCopier.java +++ b/jcache/src/main/java/com/github/benmanes/caffeine/jcache/copy/AbstractCopier.java @@ -30,12 +30,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.Arrays; import java.util.Calendar; -import java.util.Collections; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -55,16 +51,13 @@ public abstract class AbstractCopier implements Copier { private static final Set> JAVA_IMMUTABLE; static { - JAVA_IMMUTABLE = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(Boolean.class, - Byte.class, Character.class, Double.class, Float.class, Short.class, Integer.class, - Long.class, BigInteger.class, BigDecimal.class, String.class, Class.class, UUID.class, - URL.class, URI.class, Pattern.class, Inet4Address.class, Inet6Address.class, - InetSocketAddress.class, LocalDate.class, LocalTime.class, LocalDateTime.class, - Instant.class, Duration.class))); - Map, Function> strategies = new HashMap<>(); - strategies.put(Calendar.class, o -> ((Calendar) o).clone()); - strategies.put(Date.class, o -> ((Date) o).clone()); - JAVA_DEEP_COPY = Collections.unmodifiableMap(strategies); + JAVA_IMMUTABLE = Set.of(Boolean.class, Byte.class, Character.class, Double.class, Float.class, + Short.class, Integer.class, Long.class, BigInteger.class, BigDecimal.class, String.class, + Class.class, UUID.class, URL.class, URI.class, Pattern.class, Inet4Address.class, + Inet6Address.class, InetSocketAddress.class, LocalDate.class, LocalTime.class, + LocalDateTime.class, Instant.class, Duration.class); + JAVA_DEEP_COPY = Map.of(Date.class, o -> ((Date) o).clone(), + Calendar.class, o -> ((Calendar) o).clone()); } private final Set> immutableClasses; diff --git a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/copy/JavaSerializationCopierTest.java b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/copy/JavaSerializationCopierTest.java index a0fa5b1794..cce0fdcbcb 100644 --- a/jcache/src/test/java/com/github/benmanes/caffeine/jcache/copy/JavaSerializationCopierTest.java +++ b/jcache/src/test/java/com/github/benmanes/caffeine/jcache/copy/JavaSerializationCopierTest.java @@ -27,76 +27,98 @@ import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * @author ben.manes@gmail.com (Ben Manes) */ public final class JavaSerializationCopierTest { - final Copier copier = new JavaSerializationCopier(); - @Test(expectedExceptions = NullPointerException.class) - public void null_object() { - copy(null); + @Test(dataProvider = "nullArgs", expectedExceptions = NullPointerException.class) + public void constructor_null(Set> immutableClasses, + Map, Function> deepCopyStrategies) { + new JavaSerializationCopier(immutableClasses, deepCopyStrategies); } - @Test(expectedExceptions = NullPointerException.class) - public void null_classLoader() { + @Test(dataProvider = "copier", expectedExceptions = NullPointerException.class) + public void null_object(Copier copier) { + copy(copier, null); + } + + @Test(dataProvider = "copier", expectedExceptions = NullPointerException.class) + public void null_classLoader(Copier copier) { copier.copy(1, null); } - @Test(expectedExceptions = UncheckedIOException.class) - public void notSerializable() { - copy(new ByteArrayInputStream(new byte[0])); + @Test(dataProvider = "copier", expectedExceptions = UncheckedIOException.class) + public void notSerializable(Copier copier) { + copy(copier, new ByteArrayInputStream(new byte[0])); } - @Test - public void mutable() { + @Test(dataProvider = "copier") + public void mutable(Copier copier) { List ints = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4)); - assertThat(copy(ints), is(equalTo(ints))); + assertThat(copy(copier, ints), is(equalTo(ints))); } @Test public void immutable() { String text = "test"; - assertThat(copy(text), is(sameInstance(text))); + assertThat(copy(new JavaSerializationCopier(), text), is(sameInstance(text))); } - @Test + @Test(dataProvider = "copier") @SuppressWarnings({"JdkObsolete", "JavaUtilDate"}) - public void deepCopy_date() { + public void deepCopy_date(Copier copier) { Date date = new Date(); - assertThat(copy(date), is(equalTo(date))); + assertThat(copy(copier, date), is(equalTo(date))); } - @Test + @Test(dataProvider = "copier") @SuppressWarnings({"JdkObsolete", "JavaUtilDate"}) - public void deepCopy_calendar() { + public void deepCopy_calendar(Copier copier) { Calendar calendar = Calendar.getInstance(); calendar.setTime(new Date()); - assertThat(copy(calendar), is(equalTo(calendar))); + assertThat(copy(copier, calendar), is(equalTo(calendar))); } - @Test - public void array_primitive() { + @Test(dataProvider = "copier") + public void array_primitive(Copier copier) { int[] ints = { 0, 1, 2, 3, 4 }; - assertThat(copy(ints), is(equalTo(ints))); + assertThat(copy(copier, ints), is(equalTo(ints))); } - @Test - public void array_immutable() { + @Test(dataProvider = "copier") + public void array_immutable(Copier copier) { Integer[] ints = { 0, 1, 2, 3, 4 }; - assertThat(copy(ints), is(equalTo(ints))); + assertThat(copy(copier, ints), is(equalTo(ints))); } - @Test - public void array_mutable() { + @Test(dataProvider = "copier") + public void array_mutable(Copier copier) { Object array = new Object[] { new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4)) }; - assertThat(copy(array), is(equalTo(array))); + assertThat(copy(copier, array), is(equalTo(array))); } - private T copy(T object) { + private T copy(Copier copier, T object) { return copier.copy(object, Thread.currentThread().getContextClassLoader()); } + + @DataProvider(name = "copier") + public Object[] providesCopiers() { + return new Object[] { + new JavaSerializationCopier(), + new JavaSerializationCopier(Set.of(), Map.of()) + }; + } + + @DataProvider(name = "nullArgs") + public Object[][] providesNullArgs() { + return new Object[][] { { null, null }, { null, Map.of() }, { Set.of(), null } }; + } }