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