• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.base;
18 
19 import static com.google.common.testing.SerializableTester.reserialize;
20 import static com.google.common.truth.Truth.assertThat;
21 import static org.junit.Assert.assertThrows;
22 
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.annotations.GwtIncompatible;
25 import com.google.common.annotations.J2ktIncompatible;
26 import com.google.common.collect.Lists;
27 import com.google.common.testing.ClassSanityTester;
28 import com.google.common.testing.EqualsTester;
29 import java.io.Serializable;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.concurrent.TimeUnit;
33 import java.util.concurrent.TimeoutException;
34 import java.util.concurrent.atomic.AtomicInteger;
35 import java.util.concurrent.atomic.AtomicReference;
36 import junit.framework.TestCase;
37 
38 /**
39  * Tests com.google.common.base.Suppliers.
40  *
41  * @author Laurence Gonsalves
42  * @author Harry Heymann
43  */
44 @ElementTypesAreNonnullByDefault
45 @GwtCompatible(emulated = true)
46 public class SuppliersTest extends TestCase {
47 
48   static class CountingSupplier implements Supplier<Integer> {
49     int calls = 0;
50 
51     @Override
get()52     public Integer get() {
53       calls++;
54       return calls * 10;
55     }
56 
57     @Override
toString()58     public String toString() {
59       return "CountingSupplier";
60     }
61   }
62 
63   static class ThrowingSupplier implements Supplier<Integer> {
64     @Override
get()65     public Integer get() {
66       throw new NullPointerException();
67     }
68   }
69 
70   static class SerializableCountingSupplier extends CountingSupplier implements Serializable {
71     private static final long serialVersionUID = 0L;
72   }
73 
74   static class SerializableThrowingSupplier extends ThrowingSupplier implements Serializable {
75     private static final long serialVersionUID = 0L;
76   }
77 
checkMemoize(CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)78   static void checkMemoize(CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) {
79     // the underlying supplier hasn't executed yet
80     assertEquals(0, countingSupplier.calls);
81 
82     assertEquals(10, (int) memoizedSupplier.get());
83 
84     // now it has
85     assertEquals(1, countingSupplier.calls);
86 
87     assertEquals(10, (int) memoizedSupplier.get());
88 
89     // it still should only have executed once due to memoization
90     assertEquals(1, countingSupplier.calls);
91   }
92 
testMemoize()93   public void testMemoize() {
94     memoizeTest(new CountingSupplier());
95     memoizeTest(new SerializableCountingSupplier());
96   }
97 
memoizeTest(CountingSupplier countingSupplier)98   private void memoizeTest(CountingSupplier countingSupplier) {
99     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
100     checkMemoize(countingSupplier, memoizedSupplier);
101   }
102 
testMemoize_redudantly()103   public void testMemoize_redudantly() {
104     memoize_redudantlyTest(new CountingSupplier());
105     memoize_redudantlyTest(new SerializableCountingSupplier());
106   }
107 
memoize_redudantlyTest(CountingSupplier countingSupplier)108   private void memoize_redudantlyTest(CountingSupplier countingSupplier) {
109     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
110     assertSame(memoizedSupplier, Suppliers.memoize(memoizedSupplier));
111   }
112 
testMemoizeExceptionThrown()113   public void testMemoizeExceptionThrown() {
114     memoizeExceptionThrownTest(new ThrowingSupplier());
115     memoizeExceptionThrownTest(new SerializableThrowingSupplier());
116   }
117 
memoizeExceptionThrownTest(ThrowingSupplier throwingSupplier)118   private void memoizeExceptionThrownTest(ThrowingSupplier throwingSupplier) {
119     Supplier<Integer> memoizedSupplier = Suppliers.memoize(throwingSupplier);
120     // call get() twice to make sure that memoization doesn't interfere
121     // with throwing the exception
122     for (int i = 0; i < 2; i++) {
123       try {
124         memoizedSupplier.get();
125         fail("failed to throw NullPointerException");
126       } catch (NullPointerException e) {
127         // this is what should happen
128       }
129     }
130   }
131 
132   @J2ktIncompatible
133   @GwtIncompatible // SerializableTester
testMemoizeNonSerializable()134   public void testMemoizeNonSerializable() throws Exception {
135     CountingSupplier countingSupplier = new CountingSupplier();
136     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
137     assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)");
138     checkMemoize(countingSupplier, memoizedSupplier);
139     // Calls to the original memoized supplier shouldn't affect its copy.
140     Object unused = memoizedSupplier.get();
141     assertThat(memoizedSupplier.toString())
142         .isEqualTo("Suppliers.memoize(<supplier that returned 10>)");
143 
144     // Should get an exception when we try to serialize.
145     RuntimeException ex = assertThrows(RuntimeException.class, () -> reserialize(memoizedSupplier));
146     assertThat(ex).hasCauseThat().isInstanceOf(java.io.NotSerializableException.class);
147   }
148 
149   @J2ktIncompatible
150   @GwtIncompatible // SerializableTester
testMemoizeSerializable()151   public void testMemoizeSerializable() throws Exception {
152     SerializableCountingSupplier countingSupplier = new SerializableCountingSupplier();
153     Supplier<Integer> memoizedSupplier = Suppliers.memoize(countingSupplier);
154     assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)");
155     checkMemoize(countingSupplier, memoizedSupplier);
156     // Calls to the original memoized supplier shouldn't affect its copy.
157     Object unused = memoizedSupplier.get();
158     assertThat(memoizedSupplier.toString())
159         .isEqualTo("Suppliers.memoize(<supplier that returned 10>)");
160 
161     Supplier<Integer> copy = reserialize(memoizedSupplier);
162     Object unused2 = memoizedSupplier.get();
163 
164     CountingSupplier countingCopy =
165         (CountingSupplier) ((Suppliers.MemoizingSupplier<Integer>) copy).delegate;
166     checkMemoize(countingCopy, copy);
167   }
168 
testCompose()169   public void testCompose() {
170     Supplier<Integer> fiveSupplier =
171         new Supplier<Integer>() {
172           @Override
173           public Integer get() {
174             return 5;
175           }
176         };
177 
178     Function<Number, Integer> intValueFunction =
179         new Function<Number, Integer>() {
180           @Override
181           public Integer apply(Number x) {
182             return x.intValue();
183           }
184         };
185 
186     Supplier<Integer> squareSupplier = Suppliers.compose(intValueFunction, fiveSupplier);
187 
188     assertEquals(Integer.valueOf(5), squareSupplier.get());
189   }
190 
testComposeWithLists()191   public void testComposeWithLists() {
192     Supplier<ArrayList<Integer>> listSupplier =
193         new Supplier<ArrayList<Integer>>() {
194           @Override
195           public ArrayList<Integer> get() {
196             return Lists.newArrayList(0);
197           }
198         };
199 
200     Function<List<Integer>, List<Integer>> addElementFunction =
201         new Function<List<Integer>, List<Integer>>() {
202           @Override
203           public List<Integer> apply(List<Integer> list) {
204             ArrayList<Integer> result = Lists.newArrayList(list);
205             result.add(1);
206             return result;
207           }
208         };
209 
210     Supplier<List<Integer>> addSupplier = Suppliers.compose(addElementFunction, listSupplier);
211 
212     List<Integer> result = addSupplier.get();
213     assertEquals(Integer.valueOf(0), result.get(0));
214     assertEquals(Integer.valueOf(1), result.get(1));
215   }
216 
217   @J2ktIncompatible
218   @GwtIncompatible // Thread.sleep
testMemoizeWithExpiration()219   public void testMemoizeWithExpiration() throws InterruptedException {
220     CountingSupplier countingSupplier = new CountingSupplier();
221 
222     Supplier<Integer> memoizedSupplier =
223         Suppliers.memoizeWithExpiration(countingSupplier, 75, TimeUnit.MILLISECONDS);
224 
225     checkExpiration(countingSupplier, memoizedSupplier);
226   }
227 
228   @J2ktIncompatible
229   @GwtIncompatible // Thread.sleep, SerializationTester
testMemoizeWithExpirationSerialized()230   public void testMemoizeWithExpirationSerialized() throws InterruptedException {
231     SerializableCountingSupplier countingSupplier = new SerializableCountingSupplier();
232 
233     Supplier<Integer> memoizedSupplier =
234         Suppliers.memoizeWithExpiration(countingSupplier, 75, TimeUnit.MILLISECONDS);
235     // Calls to the original memoized supplier shouldn't affect its copy.
236     Object unused = memoizedSupplier.get();
237 
238     Supplier<Integer> copy = reserialize(memoizedSupplier);
239     Object unused2 = memoizedSupplier.get();
240 
241     CountingSupplier countingCopy =
242         (CountingSupplier) ((Suppliers.ExpiringMemoizingSupplier<Integer>) copy).delegate;
243     checkExpiration(countingCopy, copy);
244   }
245 
246   @J2ktIncompatible
247   @GwtIncompatible // Thread.sleep
checkExpiration( CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)248   private void checkExpiration(
249       CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier)
250       throws InterruptedException {
251     // the underlying supplier hasn't executed yet
252     assertEquals(0, countingSupplier.calls);
253 
254     assertEquals(10, (int) memoizedSupplier.get());
255     // now it has
256     assertEquals(1, countingSupplier.calls);
257 
258     assertEquals(10, (int) memoizedSupplier.get());
259     // it still should only have executed once due to memoization
260     assertEquals(1, countingSupplier.calls);
261 
262     Thread.sleep(150);
263 
264     assertEquals(20, (int) memoizedSupplier.get());
265     // old value expired
266     assertEquals(2, countingSupplier.calls);
267 
268     assertEquals(20, (int) memoizedSupplier.get());
269     // it still should only have executed twice due to memoization
270     assertEquals(2, countingSupplier.calls);
271   }
272 
testOfInstanceSuppliesSameInstance()273   public void testOfInstanceSuppliesSameInstance() {
274     Object toBeSupplied = new Object();
275     Supplier<Object> objectSupplier = Suppliers.ofInstance(toBeSupplied);
276     assertSame(toBeSupplied, objectSupplier.get());
277     assertSame(toBeSupplied, objectSupplier.get()); // idempotent
278   }
279 
testOfInstanceSuppliesNull()280   public void testOfInstanceSuppliesNull() {
281     Supplier<Integer> nullSupplier = Suppliers.ofInstance(null);
282     assertNull(nullSupplier.get());
283   }
284 
285   @J2ktIncompatible
286   @GwtIncompatible // Thread
testExpiringMemoizedSupplierThreadSafe()287   public void testExpiringMemoizedSupplierThreadSafe() throws Throwable {
288     Function<Supplier<Boolean>, Supplier<Boolean>> memoizer =
289         new Function<Supplier<Boolean>, Supplier<Boolean>>() {
290           @Override
291           public Supplier<Boolean> apply(Supplier<Boolean> supplier) {
292             return Suppliers.memoizeWithExpiration(supplier, Long.MAX_VALUE, TimeUnit.NANOSECONDS);
293           }
294         };
295     testSupplierThreadSafe(memoizer);
296   }
297 
298   @J2ktIncompatible
299   @GwtIncompatible // Thread
testMemoizedSupplierThreadSafe()300   public void testMemoizedSupplierThreadSafe() throws Throwable {
301     Function<Supplier<Boolean>, Supplier<Boolean>> memoizer =
302         new Function<Supplier<Boolean>, Supplier<Boolean>>() {
303           @Override
304           public Supplier<Boolean> apply(Supplier<Boolean> supplier) {
305             return Suppliers.memoize(supplier);
306           }
307         };
308     testSupplierThreadSafe(memoizer);
309   }
310 
311   @J2ktIncompatible
312   @GwtIncompatible // Thread
testSupplierThreadSafe(Function<Supplier<Boolean>, Supplier<Boolean>> memoizer)313   private void testSupplierThreadSafe(Function<Supplier<Boolean>, Supplier<Boolean>> memoizer)
314       throws Throwable {
315     final AtomicInteger count = new AtomicInteger(0);
316     final AtomicReference<Throwable> thrown = new AtomicReference<>(null);
317     final int numThreads = 3;
318     final Thread[] threads = new Thread[numThreads];
319     final long timeout = TimeUnit.SECONDS.toNanos(60);
320 
321     final Supplier<Boolean> supplier =
322         new Supplier<Boolean>() {
323           boolean isWaiting(Thread thread) {
324             switch (thread.getState()) {
325               case BLOCKED:
326               case WAITING:
327               case TIMED_WAITING:
328                 return true;
329               default:
330                 return false;
331             }
332           }
333 
334           int waitingThreads() {
335             int waitingThreads = 0;
336             for (Thread thread : threads) {
337               if (isWaiting(thread)) {
338                 waitingThreads++;
339               }
340             }
341             return waitingThreads;
342           }
343 
344           @Override
345           public Boolean get() {
346             // Check that this method is called exactly once, by the first
347             // thread to synchronize.
348             long t0 = System.nanoTime();
349             while (waitingThreads() != numThreads - 1) {
350               if (System.nanoTime() - t0 > timeout) {
351                 thrown.set(
352                     new TimeoutException(
353                         "timed out waiting for other threads to block"
354                             + " synchronizing on supplier"));
355                 break;
356               }
357               Thread.yield();
358             }
359             count.getAndIncrement();
360             return Boolean.TRUE;
361           }
362         };
363 
364     final Supplier<Boolean> memoizedSupplier = memoizer.apply(supplier);
365 
366     for (int i = 0; i < numThreads; i++) {
367       threads[i] =
368           new Thread() {
369             @Override
370             public void run() {
371               assertSame(Boolean.TRUE, memoizedSupplier.get());
372             }
373           };
374     }
375     for (Thread t : threads) {
376       t.start();
377     }
378     for (Thread t : threads) {
379       t.join();
380     }
381 
382     if (thrown.get() != null) {
383       throw thrown.get();
384     }
385     assertEquals(1, count.get());
386   }
387 
388   @J2ktIncompatible
389   @GwtIncompatible // Thread
testSynchronizedSupplierThreadSafe()390   public void testSynchronizedSupplierThreadSafe() throws InterruptedException {
391     final Supplier<Integer> nonThreadSafe =
392         new Supplier<Integer>() {
393           int counter = 0;
394 
395           @Override
396           public Integer get() {
397             int nextValue = counter + 1;
398             Thread.yield();
399             counter = nextValue;
400             return counter;
401           }
402         };
403 
404     final int numThreads = 10;
405     final int iterations = 1000;
406     Thread[] threads = new Thread[numThreads];
407     for (int i = 0; i < numThreads; i++) {
408       threads[i] =
409           new Thread() {
410             @Override
411             public void run() {
412               for (int j = 0; j < iterations; j++) {
413                 Object unused = Suppliers.synchronizedSupplier(nonThreadSafe).get();
414               }
415             }
416           };
417     }
418     for (Thread t : threads) {
419       t.start();
420     }
421     for (Thread t : threads) {
422       t.join();
423     }
424 
425     assertEquals(numThreads * iterations + 1, (int) nonThreadSafe.get());
426   }
427 
testSupplierFunction()428   public void testSupplierFunction() {
429     Supplier<Integer> supplier = Suppliers.ofInstance(14);
430     Function<Supplier<Integer>, Integer> supplierFunction = Suppliers.supplierFunction();
431 
432     assertEquals(14, (int) supplierFunction.apply(supplier));
433   }
434 
435   @J2ktIncompatible
436   @GwtIncompatible // SerializationTester
testSerialization()437   public void testSerialization() {
438     assertEquals(Integer.valueOf(5), reserialize(Suppliers.ofInstance(5)).get());
439     assertEquals(
440         Integer.valueOf(5),
441         reserialize(Suppliers.compose(Functions.identity(), Suppliers.ofInstance(5))).get());
442     assertEquals(Integer.valueOf(5), reserialize(Suppliers.memoize(Suppliers.ofInstance(5))).get());
443     assertEquals(
444         Integer.valueOf(5),
445         reserialize(Suppliers.memoizeWithExpiration(Suppliers.ofInstance(5), 30, TimeUnit.SECONDS))
446             .get());
447     assertEquals(
448         Integer.valueOf(5),
449         reserialize(Suppliers.synchronizedSupplier(Suppliers.ofInstance(5))).get());
450   }
451 
452   @J2ktIncompatible
453   @GwtIncompatible // reflection
testSuppliersNullChecks()454   public void testSuppliersNullChecks() throws Exception {
455     new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class).testNulls();
456   }
457 
458   @J2ktIncompatible
459   @GwtIncompatible // reflection
460   @AndroidIncompatible // TODO(cpovirk): ClassNotFoundException: com.google.common.base.Function
testSuppliersSerializable()461   public void testSuppliersSerializable() throws Exception {
462     new ClassSanityTester().forAllPublicStaticMethods(Suppliers.class).testSerializable();
463   }
464 
testOfInstance_equals()465   public void testOfInstance_equals() {
466     new EqualsTester()
467         .addEqualityGroup(Suppliers.ofInstance("foo"), Suppliers.ofInstance("foo"))
468         .addEqualityGroup(Suppliers.ofInstance("bar"))
469         .testEquals();
470   }
471 
testCompose_equals()472   public void testCompose_equals() {
473     new EqualsTester()
474         .addEqualityGroup(
475             Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("foo")),
476             Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("foo")))
477         .addEqualityGroup(Suppliers.compose(Functions.constant(2), Suppliers.ofInstance("foo")))
478         .addEqualityGroup(Suppliers.compose(Functions.constant(1), Suppliers.ofInstance("bar")))
479         .testEquals();
480   }
481 }
482